| 1 | /* -*- Mode: C; c-basic-offset:4 ; -*- */ |
|---|
| 2 | /* |
|---|
| 3 | * |
|---|
| 4 | * (C) 2001 by Argonne National Laboratory. |
|---|
| 5 | * See COPYRIGHT in top-level directory. |
|---|
| 6 | */ |
|---|
| 7 | |
|---|
| 8 | #include "mpiimpl.h" |
|---|
| 9 | #include "errcodes.h" |
|---|
| 10 | |
|---|
| 11 | #include <string.h> |
|---|
| 12 | |
|---|
| 13 | /* |
|---|
| 14 | * This file contains the routines needed to implement the MPI routines that |
|---|
| 15 | * can add error classes and codes during runtime. This file is organized |
|---|
| 16 | * so that applications that do not use the MPI-2 routines to create new |
|---|
| 17 | * error codes will not load any of this code. |
|---|
| 18 | * |
|---|
| 19 | * ROMIO has been customized to provide error messages with the same tools |
|---|
| 20 | * as the rest of MPICH2 and will not rely on the dynamically assigned |
|---|
| 21 | * error classes. This leaves all of the classes and codes for the user. |
|---|
| 22 | * |
|---|
| 23 | * Because we have customized ROMIO, we do not need to implement |
|---|
| 24 | * instance-specific messages for the dynamic error codes. |
|---|
| 25 | */ |
|---|
| 26 | |
|---|
| 27 | /* Local data structures. |
|---|
| 28 | A message may be associated with each class and code. |
|---|
| 29 | Since we limit the number of user-defined classes and code (no more |
|---|
| 30 | than 256 of each), we allocate an array of pointers to the messages here. |
|---|
| 31 | |
|---|
| 32 | We *could* allow 256 codes with each class. However, we don't expect |
|---|
| 33 | any need for this many codes, so we simply allow 256 (actually |
|---|
| 34 | ERROR_MAX_NCODE) codes, and distribute these among the error codes. |
|---|
| 35 | |
|---|
| 36 | A user-defined error code has the following format. The ERROR_xxx |
|---|
| 37 | is the macro that may be used to extract the data (usually a MASK and |
|---|
| 38 | a (right)shift) |
|---|
| 39 | |
|---|
| 40 | [0-6] Class (same as predefined error classes); ERROR_CLASS_MASK |
|---|
| 41 | [7] Is dynamic; ERROR_DYN_MASK and ERROR_DYN_SHIFT |
|---|
| 42 | [8-18] Code index (for messages); ERROR_GENERIC_MASK and ERROR_GENERIC_SHIFT |
|---|
| 43 | [19-31] Zero (unused but defined as zero) |
|---|
| 44 | */ |
|---|
| 45 | |
|---|
| 46 | static int not_initialized = 1; /* This allows us to use atomic decr */ |
|---|
| 47 | static const char *(user_class_msgs[ERROR_MAX_NCLASS]) = { 0 }; |
|---|
| 48 | static const char *(user_code_msgs[ERROR_MAX_NCODE]) = { 0 }; |
|---|
| 49 | static int first_free_class = 0; |
|---|
| 50 | static int first_free_code = 1; /* code 0 is reserved */ |
|---|
| 51 | |
|---|
| 52 | /* Forward reference */ |
|---|
| 53 | const char *MPIR_Err_get_dynerr_string( int code ); |
|---|
| 54 | |
|---|
| 55 | /* This external allows this package to define the routine that converts |
|---|
| 56 | dynamically assigned codes and classes to their corresponding strings. |
|---|
| 57 | A cleaner implementation could replace this exposed global with a method |
|---|
| 58 | defined in the error_string.c file that allowed this package to set |
|---|
| 59 | the routine. */ |
|---|
| 60 | |
|---|
| 61 | static int MPIR_Dynerrcodes_finalize( void * ); |
|---|
| 62 | |
|---|
| 63 | /* Local routine to initialize the data structures for the dynamic |
|---|
| 64 | error classes and codes. |
|---|
| 65 | |
|---|
| 66 | MPIR_Init_err_dyncodes is called if not_initialized is true. |
|---|
| 67 | Because all of the routines in this file are called by the |
|---|
| 68 | MPI_Add_error_xxx routines, and those routines use the SINGLE_CS |
|---|
| 69 | when the implementation is multithreaded, these routines (until |
|---|
| 70 | we implement finer-grain thread-synchronization) need not worry about |
|---|
| 71 | multiple threads |
|---|
| 72 | */ |
|---|
| 73 | static void MPIR_Init_err_dyncodes( void ) |
|---|
| 74 | { |
|---|
| 75 | int i; |
|---|
| 76 | |
|---|
| 77 | /* FIXME: Does this need a thread-safe init? */ |
|---|
| 78 | not_initialized = 0; |
|---|
| 79 | |
|---|
| 80 | for (i=0; i<ERROR_MAX_NCLASS; i++) { |
|---|
| 81 | user_class_msgs[i] = 0; |
|---|
| 82 | } |
|---|
| 83 | for (i=0; i<ERROR_MAX_NCODE; i++) { |
|---|
| 84 | user_code_msgs[i] = 0; |
|---|
| 85 | } |
|---|
| 86 | /* Set the routine to provides access to the dynamically created |
|---|
| 87 | error strings */ |
|---|
| 88 | MPIR_Process.errcode_to_string = MPIR_Err_get_dynerr_string; |
|---|
| 89 | |
|---|
| 90 | /* Add a finalize handler to free any allocated space */ |
|---|
| 91 | MPIR_Add_finalize( MPIR_Dynerrcodes_finalize, (void*)0, 9 ); |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | /* |
|---|
| 95 | MPIR_Err_set_msg - Change the message for an error code or class |
|---|
| 96 | |
|---|
| 97 | Input Parameter: |
|---|
| 98 | + code - Error code or class |
|---|
| 99 | - msg - New message to use |
|---|
| 100 | |
|---|
| 101 | Notes: |
|---|
| 102 | This routine is needed to implement 'MPI_Add_error_string'. |
|---|
| 103 | */ |
|---|
| 104 | int MPIR_Err_set_msg( int code, const char *msg_string ) |
|---|
| 105 | { |
|---|
| 106 | int errcode, errclass; |
|---|
| 107 | size_t msg_len; |
|---|
| 108 | char *str; |
|---|
| 109 | static const char FCNAME[] = "MPIR_Err_set_msg"; |
|---|
| 110 | |
|---|
| 111 | /* --BEGIN ERROR HANDLING-- */ |
|---|
| 112 | if (not_initialized) { |
|---|
| 113 | /* Just to keep the rest of the code more robust, we'll |
|---|
| 114 | initialize the dynamic error codes *anyway*, but this is |
|---|
| 115 | an error (see MPI_Add_error_string in the standard) */ |
|---|
| 116 | MPIR_Init_err_dyncodes(); |
|---|
| 117 | return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, |
|---|
| 118 | "MPIR_Err_set_msg", __LINE__, |
|---|
| 119 | MPI_ERR_ARG, "**argerrcode", |
|---|
| 120 | "**argerrcode %d", code ); |
|---|
| 121 | } |
|---|
| 122 | /* --END ERROR HANDLING-- */ |
|---|
| 123 | |
|---|
| 124 | /* Error strings are attached to a particular error code, not class. |
|---|
| 125 | As a special case, if the code is 0, we use the class message */ |
|---|
| 126 | errclass = code & ERROR_CLASS_MASK; |
|---|
| 127 | errcode = (code & ERROR_GENERIC_MASK) >> ERROR_GENERIC_SHIFT; |
|---|
| 128 | |
|---|
| 129 | /* --BEGIN ERROR HANDLING-- */ |
|---|
| 130 | if (code & ~(ERROR_CLASS_MASK | ERROR_DYN_MASK | ERROR_GENERIC_MASK)) { |
|---|
| 131 | /* Check for invalid error code */ |
|---|
| 132 | return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, |
|---|
| 133 | FCNAME, __LINE__, |
|---|
| 134 | MPI_ERR_ARG, "**argerrcode", |
|---|
| 135 | "**argerrcode %d", code ); |
|---|
| 136 | } |
|---|
| 137 | /* --END ERROR HANDLING-- */ |
|---|
| 138 | |
|---|
| 139 | /* --------------------------------------------------------------------- */ |
|---|
| 140 | msg_len = strlen( msg_string ); |
|---|
| 141 | str = (char *)MPIU_Malloc( msg_len + 1 ); |
|---|
| 142 | /* --BEGIN ERROR HANDLING-- */ |
|---|
| 143 | if (!str) { |
|---|
| 144 | return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, |
|---|
| 145 | FCNAME, __LINE__, MPI_ERR_OTHER, |
|---|
| 146 | "**nomem", "**nomem %s %d", |
|---|
| 147 | "error message string", msg_len ); |
|---|
| 148 | } |
|---|
| 149 | /* --END ERROR HANDLING-- */ |
|---|
| 150 | |
|---|
| 151 | /* --------------------------------------------------------------------- */ |
|---|
| 152 | MPIU_Strncpy( str, msg_string, msg_len + 1 ); |
|---|
| 153 | if (errcode) { |
|---|
| 154 | if (errcode < first_free_code) { |
|---|
| 155 | if (user_code_msgs[errcode]) { |
|---|
| 156 | MPIU_Free( (void*)(user_code_msgs[errcode]) ); |
|---|
| 157 | } |
|---|
| 158 | user_code_msgs[errcode] = (const char *)str; |
|---|
| 159 | } |
|---|
| 160 | else { |
|---|
| 161 | /* FIXME : Unallocated error code? */ |
|---|
| 162 | MPIU_Free( str ); |
|---|
| 163 | } |
|---|
| 164 | } |
|---|
| 165 | else { |
|---|
| 166 | if (errclass < first_free_class) { |
|---|
| 167 | if (user_class_msgs[errclass]) { |
|---|
| 168 | MPIU_Free( (void*)(user_class_msgs[errclass]) ); |
|---|
| 169 | } |
|---|
| 170 | user_class_msgs[errclass] = (const char *)str; |
|---|
| 171 | } |
|---|
| 172 | else { |
|---|
| 173 | /* FIXME : Unallocated error code? */ |
|---|
| 174 | MPIU_Free( str ); |
|---|
| 175 | } |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | return MPI_SUCCESS; |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | /* |
|---|
| 182 | MPIR_Err_add_class - Creata a new error class |
|---|
| 183 | |
|---|
| 184 | Return value: |
|---|
| 185 | An error class. Returns -1 if no more classes are available. |
|---|
| 186 | |
|---|
| 187 | Notes: |
|---|
| 188 | This is used to implement 'MPI_Add_error_class'; it may also be used by a |
|---|
| 189 | device to add device-specific error classes. |
|---|
| 190 | |
|---|
| 191 | Predefined classes are handled directly; this routine is not used to |
|---|
| 192 | initialize the predefined MPI error classes. This is done to reduce the |
|---|
| 193 | number of steps that must be executed when starting an MPI program. |
|---|
| 194 | |
|---|
| 195 | This routine should be run within a SINGLE_CS in the multithreaded case. |
|---|
| 196 | */ |
|---|
| 197 | int MPIR_Err_add_class(void) |
|---|
| 198 | { |
|---|
| 199 | int new_class; |
|---|
| 200 | |
|---|
| 201 | if (not_initialized) |
|---|
| 202 | MPIR_Init_err_dyncodes(); |
|---|
| 203 | |
|---|
| 204 | /* Get new class */ |
|---|
| 205 | MPIR_Fetch_and_increment( &first_free_class, &new_class ); |
|---|
| 206 | |
|---|
| 207 | /* --BEGIN ERROR HANDLING-- */ |
|---|
| 208 | if (new_class >= ERROR_MAX_NCLASS) { |
|---|
| 209 | /* Fail if out of classes */ |
|---|
| 210 | return -1; |
|---|
| 211 | } |
|---|
| 212 | /* --END ERROR HANDLING-- */ |
|---|
| 213 | |
|---|
| 214 | /* Note that the MPI interface always adds an error class without |
|---|
| 215 | a string. */ |
|---|
| 216 | user_class_msgs[new_class] = 0; |
|---|
| 217 | |
|---|
| 218 | return (new_class | ERROR_DYN_MASK); |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | /* |
|---|
| 222 | MPIR_Err_add_code - Create a new error code that is associated with an |
|---|
| 223 | existing error class |
|---|
| 224 | |
|---|
| 225 | Input Parameters: |
|---|
| 226 | . class - Error class to which the code belongs. |
|---|
| 227 | |
|---|
| 228 | Return value: |
|---|
| 229 | An error code. |
|---|
| 230 | |
|---|
| 231 | Notes: |
|---|
| 232 | This is used to implement 'MPI_Add_error_code'; it may also be used by a |
|---|
| 233 | device to add device-specific error codes. |
|---|
| 234 | |
|---|
| 235 | */ |
|---|
| 236 | int MPIR_Err_add_code( int class ) |
|---|
| 237 | { |
|---|
| 238 | int new_code; |
|---|
| 239 | |
|---|
| 240 | /* Note that we can add codes to existing classes, so we may |
|---|
| 241 | need to initialize the dynamic error routines in this function */ |
|---|
| 242 | if (not_initialized) |
|---|
| 243 | MPIR_Init_err_dyncodes(); |
|---|
| 244 | |
|---|
| 245 | /* Get the new code */ |
|---|
| 246 | MPIR_Fetch_and_increment( &first_free_code, &new_code ); |
|---|
| 247 | /* --BEGIN ERROR HANDLING-- */ |
|---|
| 248 | if (new_code >= ERROR_MAX_NCODE) { |
|---|
| 249 | /* Fail if out of codes */ |
|---|
| 250 | return -1; |
|---|
| 251 | } |
|---|
| 252 | /* --END ERROR HANDLING-- */ |
|---|
| 253 | |
|---|
| 254 | /* Create the full error code */ |
|---|
| 255 | new_code = class | ERROR_DYN_MASK | (new_code << ERROR_GENERIC_SHIFT); |
|---|
| 256 | |
|---|
| 257 | /* FIXME: For robustness, we should make sure that the associated string |
|---|
| 258 | is initialized to null */ |
|---|
| 259 | return new_code; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | /* |
|---|
| 263 | MPIR_Err_get_dynerr_string - Get the message string that corresponds to a |
|---|
| 264 | dynamically created error class or code |
|---|
| 265 | |
|---|
| 266 | Input Parameter: |
|---|
| 267 | + code - An error class or code. If a code, it must have been created by |
|---|
| 268 | 'MPIR_Err_create_code'. |
|---|
| 269 | |
|---|
| 270 | Return value: |
|---|
| 271 | A pointer to a null-terminated text string with the corresponding error |
|---|
| 272 | message. A null return indicates an error; usually the value of 'code' is |
|---|
| 273 | neither a valid error class or code. |
|---|
| 274 | |
|---|
| 275 | Notes: |
|---|
| 276 | This routine is used to implement 'MPI_ERROR_STRING'. It is only called |
|---|
| 277 | for dynamic error codes. |
|---|
| 278 | */ |
|---|
| 279 | const char *MPIR_Err_get_dynerr_string( int code ) |
|---|
| 280 | { |
|---|
| 281 | int errcode, errclass; |
|---|
| 282 | const char *errstr = 0; |
|---|
| 283 | |
|---|
| 284 | /* Error strings are attached to a particular error code, not class. |
|---|
| 285 | As a special case, if the code is 0, we use the class message */ |
|---|
| 286 | errclass = code & ERROR_CLASS_MASK; |
|---|
| 287 | errcode = (code & ERROR_GENERIC_MASK) >> ERROR_GENERIC_SHIFT; |
|---|
| 288 | |
|---|
| 289 | if (code & ~(ERROR_CLASS_MASK | ERROR_DYN_MASK | ERROR_GENERIC_MASK)) { |
|---|
| 290 | /* Check for invalid error code */ |
|---|
| 291 | return 0; |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | if (errcode) { |
|---|
| 295 | if (errcode < first_free_code) { |
|---|
| 296 | errstr = user_code_msgs[errcode]; |
|---|
| 297 | } |
|---|
| 298 | } |
|---|
| 299 | else { |
|---|
| 300 | if (errclass < first_free_class) { |
|---|
| 301 | errstr = user_class_msgs[errclass]; |
|---|
| 302 | } |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | return errstr; |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | |
|---|
| 309 | static int MPIR_Dynerrcodes_finalize( void *p ATTRIBUTE((unused)) ) |
|---|
| 310 | { |
|---|
| 311 | int i; |
|---|
| 312 | |
|---|
| 313 | MPIU_UNREFERENCED_ARG(p); |
|---|
| 314 | |
|---|
| 315 | if (not_initialized == 0) { |
|---|
| 316 | |
|---|
| 317 | for (i=0; i<first_free_class; i++) { |
|---|
| 318 | if (user_class_msgs[i]) |
|---|
| 319 | MPIU_Free((char *) user_class_msgs[i]); |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | for (i=0; i<first_free_code; i++) { |
|---|
| 323 | if (user_code_msgs[i]) |
|---|
| 324 | MPIU_Free((char *) user_code_msgs[i]); |
|---|
| 325 | } |
|---|
| 326 | } |
|---|
| 327 | return 0; |
|---|
| 328 | } |
|---|