1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4 * University Research and Technology
5 * Corporation. All rights reserved.
6 * Copyright (c) 2004-2011 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 * University of Stuttgart. All rights reserved.
11 * Copyright (c) 2004-2005 The Regents of the University of California.
12 * All rights reserved.
13 * Copyright (c) 2008-2018 Cisco Systems, Inc. All rights reserved
14 * Copyright (c) 2008-2009 Sun Microsystems, Inc. All rights reserved.
15 * Copyright (c) 2015-2016 Intel, Inc. All rights reserved.
16 * Copyright (c) 2016 Los Alamos National Security, LLC. All rights
17 * reserved.
18 * Copyright (c) 2016 Research Organization for Information Science
19 * and Technology (RIST). All rights reserved.
20 * $COPYRIGHT$
21 *
22 * Additional copyrights may follow
23 *
24 * $HEADER$
25 */
26 /** @file **/
27
28 #ifndef OMPI_ERRHANDLER_H
29 #define OMPI_ERRHANDLER_H
30
31 #include "ompi_config.h"
32
33 #include "mpi.h"
34
35 #include "opal/prefetch.h"
36 #include "opal/class/opal_object.h"
37 #include "opal/class/opal_pointer_array.h"
38 #include "opal/mca/pmix/pmix.h"
39
40 #include "ompi/runtime/mpiruntime.h"
41 #include "ompi/errhandler/errhandler_predefined.h"
42 #include "ompi/errhandler/errcode-internal.h"
43
44 BEGIN_C_DECLS
45
46 /*
47 * These must correspond to the fortran handle indices
48 */
49 enum {
50 OMPI_ERRHANDLER_NULL_FORTRAN = 0,
51 OMPI_ERRORS_ARE_FATAL_FORTRAN,
52 OMPI_ERRORS_RETURN_FORTRAN
53 };
54
55
56 /**
57 * Typedef for all fortran errhandler functions
58 */
59 typedef void (ompi_errhandler_fortran_handler_fn_t)(MPI_Fint *,
60 MPI_Fint *, ...);
61
62 /**
63 * Typedef for generic errhandler function
64 */
65 typedef void (ompi_errhandler_generic_handler_fn_t)(void *, int *, ...);
66
67 /**
68 * Enum to denote what language the error handler was created from
69 */
70 enum ompi_errhandler_lang_t {
71 OMPI_ERRHANDLER_LANG_C,
72 OMPI_ERRHANDLER_LANG_CXX,
73 OMPI_ERRHANDLER_LANG_FORTRAN
74 };
75 typedef enum ompi_errhandler_lang_t ompi_errhandler_lang_t;
76
77
78 /**
79 * Enum used to describe what kind MPI object an error handler is used for
80 */
81 enum ompi_errhandler_type_t {
82 OMPI_ERRHANDLER_TYPE_PREDEFINED,
83 OMPI_ERRHANDLER_TYPE_COMM,
84 OMPI_ERRHANDLER_TYPE_WIN,
85 OMPI_ERRHANDLER_TYPE_FILE
86 };
87 typedef enum ompi_errhandler_type_t ompi_errhandler_type_t;
88
89
90 /*
91 * Need to forward declare this for use in ompi_errhandle_cxx_dispatch_fn_t.
92 */
93 struct ompi_errhandler_t;
94
95 /**
96 * C++ invocation function signature
97 */
98 typedef void (ompi_errhandler_cxx_dispatch_fn_t)(void *handle, int *err_code,
99 const char *message, ompi_errhandler_generic_handler_fn_t *fn);
100
101 /**
102 * Back-end type for MPI_Errorhandler.
103 */
104 struct ompi_errhandler_t {
105 opal_object_t super;
106
107 char eh_name[MPI_MAX_OBJECT_NAME];
108 /* Type of MPI object that this handler is for */
109
110 ompi_errhandler_type_t eh_mpi_object_type;
111
112 /* What language was the error handler created in */
113 ompi_errhandler_lang_t eh_lang;
114
115 /* Function pointers. Note that we *have* to have all 4 types
116 (vs., for example, a union) because the predefined errhandlers
117 can be invoked on any MPI object type, so we need callbacks for
118 all of three. */
119 MPI_Comm_errhandler_function *eh_comm_fn;
120 ompi_file_errhandler_function *eh_file_fn;
121 MPI_Win_errhandler_function *eh_win_fn;
122 ompi_errhandler_fortran_handler_fn_t *eh_fort_fn;
123
124 /* Have separate callback for C++ errhandlers. This pointer is
125 initialized to NULL and will be set explicitly by the C++
126 bindings for Create_errhandler. This function is invoked
127 when eh_lang==OMPI_ERRHANDLER_LANG_CXX so that the user's
128 callback function can be invoked with the right language
129 semantics. */
130 ompi_errhandler_cxx_dispatch_fn_t *eh_cxx_dispatch_fn;
131
132 /* index in Fortran <-> C translation array */
133 int eh_f_to_c_index;
134 };
135 typedef struct ompi_errhandler_t ompi_errhandler_t;
136
137 /**
138 * Padded struct to maintain back compatibiltiy.
139 * See ompi/communicator/communicator.h comments with struct ompi_communicator_t
140 * for full explanation why we chose the following padding construct for predefines.
141 */
142 #define PREDEFINED_ERRHANDLER_PAD 1024
143
144 struct ompi_predefined_errhandler_t {
145 struct ompi_errhandler_t eh;
146 char padding[PREDEFINED_ERRHANDLER_PAD - sizeof(ompi_errhandler_t)];
147 };
148
149 typedef struct ompi_predefined_errhandler_t ompi_predefined_errhandler_t;
150
151
152 /**
153 * Global variable for MPI_ERRHANDLER_NULL (_addr flavor is for F03 bindings)
154 */
155 OMPI_DECLSPEC extern ompi_predefined_errhandler_t ompi_mpi_errhandler_null;
156 OMPI_DECLSPEC extern ompi_predefined_errhandler_t *ompi_mpi_errhandler_null_addr;
157
158 /**
159 * Global variable for MPI_ERRORS_ARE_FATAL (_addr flavor is for F03 bindings)
160 */
161 OMPI_DECLSPEC extern ompi_predefined_errhandler_t ompi_mpi_errors_are_fatal;
162 OMPI_DECLSPEC extern ompi_predefined_errhandler_t *ompi_mpi_errors_are_fatal_addr;
163
164 /**
165 * Global variable for MPI_ERRORS_RETURN (_addr flavor is for F03 bindings)
166 */
167 OMPI_DECLSPEC extern ompi_predefined_errhandler_t ompi_mpi_errors_return;
168 OMPI_DECLSPEC extern ompi_predefined_errhandler_t *ompi_mpi_errors_return_addr;
169
170 /**
171 * Global variable for MPI::ERRORS_THROW_EXCEPTIONS. Will abort if
172 * MPI_INIT wasn't called as MPI::INIT (_addr flavor is for F03 bindings)
173 */
174 OMPI_DECLSPEC extern ompi_predefined_errhandler_t ompi_mpi_errors_throw_exceptions;
175
176 /**
177 * Table for Fortran <-> C errhandler handle conversion
178 */
179 OMPI_DECLSPEC extern opal_pointer_array_t ompi_errhandler_f_to_c_table;
180
181
182 /**
183 * Forward declaration so that we don't have to include
184 * request/request.h here.
185 */
186 struct ompi_request_t;
187
188
189 /**
190 * This is the macro to check the state of MPI and determine whether
191 * it was properly initialized and not yet finalized.
192 *
193 * This macro directly invokes the ompi_mpi_errors_are_fatal_handler()
194 * when an error occurs because MPI_COMM_WORLD does not exist (because
195 * we're before MPI_Init() or after MPI_Finalize()).
196 *
197 * NOTE: The ompi_mpi_state variable is a volatile that is set
198 * atomically in ompi_mpi_init() and ompi_mpi_finalize(). The
199 * appropriate memory barriers are done in those 2 functions such that
200 * we do not need to do a read memory barrier here (in
201 * potentially-performance-critical code paths) before reading the
202 * variable.
203 */
204 #define OMPI_ERR_INIT_FINALIZE(name) \
205 { \
206 int32_t state = ompi_mpi_state; \
207 if (OPAL_UNLIKELY(state < OMPI_MPI_STATE_INIT_COMPLETED || \
208 state > OMPI_MPI_STATE_FINALIZE_PAST_COMM_SELF_DESTRUCT)) { \
209 ompi_mpi_errors_are_fatal_comm_handler(NULL, NULL, name); \
210 } \
211 }
212
213 /**
214 * This is the macro to invoke to directly invoke an MPI error
215 * handler.
216 *
217 * @param mpi_object The MPI object to invoke the errhandler on (a
218 * comm, win, or win)
219 * @param err_code The error code
220 * @param message Any additional message; typically the name of the
221 * MPI function that is invoking the error.
222 *
223 * This macro is used when you want to directly invoke the error
224 * handler. It is exactly equivalent to calling
225 * ompi_errhandler_invoke() directly, but is provided to have a
226 * parallel invocation to OMPI_ERRHANDLER_CHECK() and OMPI_ERRHANDLER_RETURN().
227 */
228 #define OMPI_ERRHANDLER_INVOKE(mpi_object, err_code, message) \
229 ompi_errhandler_invoke((mpi_object)->error_handler, \
230 (mpi_object), \
231 (int)(mpi_object)->errhandler_type, \
232 ompi_errcode_get_mpi_code(err_code), \
233 (message));
234
235 /**
236 * Conditionally invoke an MPI error handler.
237 *
238 * @param rc The return code to check
239 * @param mpi_object The MPI object to invoke the errhandler on (a
240 * comm, win, or win)
241 * @param err_code The error code
242 * @param message Any additional message; typically the name of the
243 * MPI function that is invoking the error.
244 *
245 * This macro will invoke the error handler if the return code is not
246 * OMPI_SUCCESS.
247 */
248 #define OMPI_ERRHANDLER_CHECK(rc, mpi_object, err_code, message) \
249 if( OPAL_UNLIKELY(rc != OMPI_SUCCESS) ) { \
250 int __mpi_err_code = ompi_errcode_get_mpi_code(err_code); \
251 OPAL_CR_EXIT_LIBRARY() \
252 ompi_errhandler_invoke((mpi_object)->error_handler, \
253 (mpi_object), \
254 (int) (mpi_object)->errhandler_type, \
255 (__mpi_err_code), \
256 (message)); \
257 return (__mpi_err_code); \
258 }
259
260 /**
261 * Conditionally invoke an MPI error handler; if there is no error,
262 * return MPI_SUCCESS.
263 *
264 * @param rc The return code to check
265 * @param mpi_object The MPI object to invoke the errhandler on (a
266 * comm, win, or win)
267 * @param err_code The error code
268 * @param message Any additional message; typically the name of the
269 * MPI function that is invoking the error.
270 *
271 * This macro will invoke the error handler if the return code is not
272 * OMPI_SUCCESS. If the return code is OMPI_SUCCESS, then return
273 * MPI_SUCCESS.
274 */
275 #define OMPI_ERRHANDLER_RETURN(rc, mpi_object, err_code, message) \
276 OPAL_CR_EXIT_LIBRARY() \
277 if ( OPAL_UNLIKELY(OMPI_SUCCESS != rc) ) { \
278 int __mpi_err_code = ompi_errcode_get_mpi_code(err_code); \
279 ompi_errhandler_invoke((mpi_object)->error_handler, \
280 (mpi_object), \
281 (int)(mpi_object)->errhandler_type, \
282 (__mpi_err_code), \
283 (message)); \
284 return (__mpi_err_code); \
285 } else { \
286 return MPI_SUCCESS; \
287 }
288
289
290
291 /**
292 * Initialize the error handler interface.
293 *
294 * @returns OMPI_SUCCESS Upon success
295 * @returns OMPI_ERROR Otherwise
296 *
297 * Invoked from ompi_mpi_init(); sets up the error handler interface,
298 * creates the predefined MPI errorhandlers, and creates the
299 * corresopnding F2C translation table.
300 */
301 int ompi_errhandler_init(void);
302
303 /**
304 * Finalize the error handler interface.
305 *
306 * @returns OMPI_SUCCESS Always
307 *
308 * Invokes from ompi_mpi_finalize(); tears down the error handler
309 * interface, and destroys the F2C translation table.
310 */
311 int ompi_errhandler_finalize(void);
312
313 /**
314 * \internal
315 *
316 * This function should not be invoked directly; it should only be
317 * invoked by OMPI_ERRHANDLER_INVOKE(), OMPI_ERRHANDLER_CHECK(), or
318 * OMPI_ERRHANDLER_RETURN().
319 *
320 * @param errhandler The MPI_Errhandler to invoke
321 * @param mpi_object The MPI object to invoke the errhandler on (a
322 * comm, win, or win)
323 * @param type The type of the MPI object. Necessary, since
324 * you can not assign a single type to the predefined
325 * error handlers. This information is therefore
326 * stored on the MPI object itself.
327 * @param err_code The error code
328 * @param message Any additional message; typically the name of the
329 * MPI function that is invoking the error.
330 *
331 * @returns err_code The same value as the parameter
332 *
333 * This function invokes the MPI exception function on the error
334 * handler. If the errhandler was created from fortran, the error
335 * handler will be invoked with fortran linkage. Otherwise, it is
336 * invoked with C linkage.
337 *
338 * If this function returns, it returns the err_code. Note that it
339 * may not return (e.g., for MPI_ERRORS_ARE_FATAL).
340 */
341 OMPI_DECLSPEC int ompi_errhandler_invoke(ompi_errhandler_t *errhandler, void *mpi_object,
342 int type, int err_code, const char *message);
343
344
345 /**
346 * Invoke an MPI exception on the first request found in the array
347 * that has a non-MPI_SUCCESS value for MPI_ERROR in its status. It
348 * is safe to invoke this function if none of the requests have an
349 * outstanding error; MPI_SUCCESS will be returned.
350 */
351 int ompi_errhandler_request_invoke(int count,
352 struct ompi_request_t **requests,
353 const char *message);
354
355 /**
356 * Create a ompi_errhandler_t
357 *
358 * @param object_type Enum of the type of MPI object
359 * @param func Function pointer of the error handler
360 *
361 * @returns errhandler Pointer to the ompi_errorhandler_t that will be
362 * created and returned
363 *
364 * This function is called as the back-end of all the
365 * MPI_*_CREATE_ERRHANDLER functions. It creates a new
366 * ompi_errhandler_t object, initializes it to the correct object
367 * type, and sets the callback function on it.
368 *
369 * The type of the function pointer is (arbitrarily) the fortran
370 * function handler type. Since this function has to accept 4
371 * different function pointer types (lest we have 4 different
372 * functions to create errhandlers), the fortran one was picked
373 * arbitrarily. Note that (void*) is not sufficient because at
374 * least theoretically, a sizeof(void*) may not necessarily be the
375 * same as sizeof(void(*)).
376 */
377 OMPI_DECLSPEC ompi_errhandler_t *ompi_errhandler_create(ompi_errhandler_type_t object_type,
378 ompi_errhandler_generic_handler_fn_t *func,
379 ompi_errhandler_lang_t language);
380
381 /**
382 * Callback function to alert the MPI layer of an error or notification
383 * from the internal RTE and/or the resource manager.
384 *
385 * This function is used to alert the MPI layer to a specific fault detected by the
386 * runtime layer or host RM. This could be a process failure, a lost connection, or the inability
387 * to send an OOB message. The MPI layer has the option to perform whatever actions it
388 * needs to stabilize itself and continue running, abort, etc.
389 */
390 typedef struct {
391 volatile bool active;
392 int status;
393 } ompi_errhandler_errtrk_t;
394
395 OMPI_DECLSPEC void ompi_errhandler_callback(int status,
396 const opal_process_name_t *source,
397 opal_list_t *info, opal_list_t *results,
398 opal_pmix_notification_complete_fn_t cbfunc,
399 void *cbdata);
400
401 OMPI_DECLSPEC void ompi_errhandler_registration_callback(int status,
402 size_t errhandler_ref,
403 void *cbdata);
404 /**
405 * Check to see if an errhandler is intrinsic.
406 *
407 * @param errhandler The errhandler to check
408 *
409 * @returns true If the errhandler is intrinsic
410 * @returns false If the errhandler is not intrinsic
411 *
412 * Self-explanitory. This is needed in a few top-level MPI functions;
413 * this function is provided to hide the internal structure field
414 * names.
415 */
416 static inline bool ompi_errhandler_is_intrinsic(ompi_errhandler_t *errhandler)
417 {
418 if ( OMPI_ERRHANDLER_TYPE_PREDEFINED == errhandler->eh_mpi_object_type )
419 return true;
420
421 return false;
422 }
423
424 END_C_DECLS
425
426 #endif /* OMPI_ERRHANDLER_H */