1 2 /* 3 IEEE error handler for all machines. Since each OS has 4 enough slight differences we have completely separate codes for each one. 5 */ 6 7 /* 8 This feature test macro provides FE_NOMASK_ENV on GNU. It must be defined 9 at the top of the file because other headers may pull in fenv.h even when 10 not strictly necessary. Strictly speaking, we could include ONLY petscconf.h, 11 check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such 12 shenanigans ought to be unnecessary. 13 */ 14 #if !defined(_GNU_SOURCE) 15 #define _GNU_SOURCE 16 #endif 17 18 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 19 #include <signal.h> 20 21 struct PetscFPTrapLink { 22 PetscFPTrap trapmode; 23 struct PetscFPTrapLink *next; 24 }; 25 static PetscFPTrap _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */ 26 static struct PetscFPTrapLink *_trapstack; /* Any pushed states of _trapmode */ 27 28 /*@ 29 PetscFPTrapPush - push a floating point trapping mode, restored using `PetscFPTrapPop()` 30 31 Not Collective 32 33 Input Parameter: 34 . trap - `PETSC_FP_TRAP_ON` or `PETSC_FP_TRAP_OFF` or any of the values passable to `PetscSetFPTrap()` 35 36 Level: advanced 37 38 Notes: 39 This only changes the trapping if the new mode is different than the current mode. 40 41 This routine is called to turn off trapping for certain LAPACK routines that assume that dividing 42 by zero is acceptable. In particular the routine ieeeck(). 43 44 Most systems by default have all trapping turned off, but certain Fortran compilers have 45 link flags that turn on trapping before the program begins. 46 $ gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal 47 $ ifort -fpe0 48 49 .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()` 50 @*/ 51 PetscErrorCode PetscFPTrapPush(PetscFPTrap trap) 52 { 53 struct PetscFPTrapLink *link; 54 55 PetscFunctionBegin; 56 PetscCall(PetscNew(&link)); 57 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP) 58 #pragma omp critical 59 #endif 60 { 61 link->trapmode = _trapmode; 62 link->next = _trapstack; 63 _trapstack = link; 64 } 65 if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap)); 66 PetscFunctionReturn(PETSC_SUCCESS); 67 } 68 69 /*@ 70 PetscFPTrapPop - push a floating point trapping mode, to be restored using `PetscFPTrapPop()` 71 72 Not Collective 73 74 Level: advanced 75 76 .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()` 77 @*/ 78 PetscErrorCode PetscFPTrapPop(void) 79 { 80 struct PetscFPTrapLink *link; 81 82 PetscFunctionBegin; 83 if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode)); 84 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP) 85 #pragma omp critical 86 #endif 87 { 88 link = _trapstack; 89 _trapstack = _trapstack->next; 90 } 91 PetscCall(PetscFree(link)); 92 PetscFunctionReturn(PETSC_SUCCESS); 93 } 94 95 /*--------------------------------------- ---------------------------------------------------*/ 96 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP) 97 #include <floatingpoint.h> 98 99 PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **); 100 PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *)); 101 102 static struct { 103 int code_no; 104 char *name; 105 } error_codes[] = { 106 {FPE_INTDIV_TRAP, "integer divide" }, 107 {FPE_FLTOPERR_TRAP, "IEEE operand error" }, 108 {FPE_FLTOVF_TRAP, "floating point overflow" }, 109 {FPE_FLTUND_TRAP, "floating point underflow" }, 110 {FPE_FLTDIV_TRAP, "floating pointing divide" }, 111 {FPE_FLTINEX_TRAP, "inexact floating point result"}, 112 {0, "unknown error" } 113 }; 114 #define SIGPC(scp) (scp->sc_pc) 115 116 /* this function gets called if a trap has occurred and been caught */ 117 sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr) 118 { 119 int err_ind = -1; 120 PetscErrorCode ierr; 121 122 PetscFunctionBegin; 123 for (int j = 0; error_codes[j].code_no; j++) { 124 if (error_codes[j].code_no == code) err_ind = j; 125 } 126 127 if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp)); 128 else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp)); 129 130 ierr = PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 131 (void)ierr; 132 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 133 PetscFunctionReturn(PETSC_SUCCESS); 134 } 135 136 /*@ 137 PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a 138 subset of exceptions may be trapable. 139 140 Not Collective 141 142 Input Parameters: 143 . flag - values are 144 .vb 145 PETSC_FP_TRAP_OFF - do not trap any exceptions 146 PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow 147 PETSC_FP_TRAP_INDIV - integer divide by zero 148 PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number 149 PETSC_FP_TRAP_FLTOVF - overflow 150 PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems 151 PETSC_FP_TRAP_FLTDIV - floating point divide by zero 152 PETSC_FP_TRAP_FLTINEX - inexact floating point result 153 .ve 154 155 Options Database Keys: 156 . -fp_trap <off,on> - turn on or off trapping of floating point exceptions 157 158 Level: advanced 159 160 Notes: 161 Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`. 162 163 The values are bit values and may be |ed together in the function call 164 165 On systems that support it this routine causes floating point 166 overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to 167 cause a message to be printed and the program to exit. 168 169 On many common systems, the floating 170 point exception state is not preserved from the location where the trap 171 occurred through to the signal handler. In this case, the signal handler 172 will just say that an unknown floating point exception occurred and which 173 function it occurred in. If you run with -fp_trap in a debugger, it will 174 break on the line where the error occurred. On systems that support C99 175 floating point exception handling You can check which 176 exception occurred using fetestexcept(FE_ALL_EXCEPT). See fenv.h 177 (usually at /usr/include/bits/fenv.h) for the enum values on your system. 178 179 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()` 180 @*/ 181 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 182 { 183 char *out; 184 185 PetscFunctionBegin; 186 /* Clear accumulated exceptions. Used to suppress meaningless messages from f77 programs */ 187 (void)ieee_flags("clear", "exception", "all", &out); 188 if (flag == PETSC_FP_TRAP_ON) { 189 /* 190 To trap more fp exceptions, including underflow, change the line below to 191 if (ieee_handler("set","all",PetscDefaultFPTrap)) { 192 */ 193 if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n"); 194 } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 195 196 _trapmode = flag; 197 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n")); 198 PetscFunctionReturn(PETSC_SUCCESS); 199 } 200 201 /*@ 202 PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called 203 204 Not Collective 205 206 Note: 207 Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on. 208 209 Level: advanced 210 211 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()` 212 @*/ 213 PetscErrorCode PetscDetermineInitialFPTrap(void) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 /* -------------------------------------------------------------------------------------------*/ 221 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP) 222 #include <sunmath.h> 223 #include <floatingpoint.h> 224 #include <siginfo.h> 225 #include <ucontext.h> 226 227 static struct { 228 int code_no; 229 char *name; 230 } error_codes[] = { 231 {FPE_FLTINV, "invalid floating point operand"}, 232 {FPE_FLTRES, "inexact floating point result" }, 233 {FPE_FLTDIV, "division-by-zero" }, 234 {FPE_FLTUND, "floating point underflow" }, 235 {FPE_FLTOVF, "floating point overflow" }, 236 {0, "unknown error" } 237 }; 238 #define SIGPC(scp) (scp->si_addr) 239 240 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) 241 { 242 int err_ind = -1, code = scp->si_code; 243 PetscErrorCode ierr; 244 245 PetscFunctionBegin; 246 for (int j = 0; error_codes[j].code_no; j++) { 247 if (error_codes[j].code_no == code) err_ind = j; 248 } 249 250 if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp)); 251 else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp)); 252 253 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 254 (void)ierr; 255 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 256 } 257 258 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 259 { 260 char *out; 261 262 PetscFunctionBegin; 263 /* Clear accumulated exceptions. Used to suppress meaningless messages from f77 programs */ 264 (void)ieee_flags("clear", "exception", "all", &out); 265 if (flag == PETSC_FP_TRAP_ON) { 266 if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n"); 267 } else { 268 if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 269 } 270 _trapmode = flag; 271 PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n"); 272 PetscFunctionReturn(PETSC_SUCCESS); 273 } 274 275 PetscErrorCode PetscDetermineInitialFPTrap(void) 276 { 277 PetscFunctionBegin; 278 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 282 /* ------------------------------------------------------------------------------------------*/ 283 #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP) 284 #include <sigfpe.h> 285 static struct { 286 int code_no; 287 char *name; 288 } error_codes[] = { 289 {_INVALID, "IEEE operand error" }, 290 {_OVERFL, "floating point overflow" }, 291 {_UNDERFL, "floating point underflow"}, 292 {_DIVZERO, "floating point divide" }, 293 {0, "unknown error" } 294 }; 295 void PetscDefaultFPTrap(unsigned exception[], int val[]) 296 { 297 int err_ind = -1, code = exception[0]; 298 PetscErrorCode ierr; 299 300 PetscFunctionBegin; 301 for (int j = 0; error_codes[j].code_no; j++) { 302 if (error_codes[j].code_no == code) err_ind = j; 303 } 304 if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name); 305 else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code); 306 307 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 308 (void)ierr; 309 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 310 } 311 312 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 313 { 314 PetscFunctionBegin; 315 if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0); 316 else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0); 317 _trapmode = flag; 318 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n")); 319 PetscFunctionReturn(PETSC_SUCCESS); 320 } 321 322 PetscErrorCode PetscDetermineInitialFPTrap(void) 323 { 324 PetscFunctionBegin; 325 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 326 PetscFunctionReturn(PETSC_SUCCESS); 327 } 328 329 /*----------------------------------------------- --------------------------------------------*/ 330 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP) 331 /* In "fast" mode, floating point traps are imprecise and ignored. 332 This is the reason for the fptrap(FP_TRAP_SYNC) call */ 333 struct sigcontext; 334 #include <fpxcp.h> 335 #include <fptrap.h> 336 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000) 337 #define FPE_FLTOVF_TRAP (fptrap_t)(0x10000000) 338 #define FPE_FLTUND_TRAP (fptrap_t)(0x08000000) 339 #define FPE_FLTDIV_TRAP (fptrap_t)(0x04000000) 340 #define FPE_FLTINEX_TRAP (fptrap_t)(0x02000000) 341 342 static struct { 343 int code_no; 344 char *name; 345 } error_codes[] = { 346 {FPE_FLTOPERR_TRAP, "IEEE operand error" }, 347 {FPE_FLTOVF_TRAP, "floating point overflow" }, 348 {FPE_FLTUND_TRAP, "floating point underflow" }, 349 {FPE_FLTDIV_TRAP, "floating point divide" }, 350 {FPE_FLTINEX_TRAP, "inexact floating point result"}, 351 < {0, "unknown error" } 352 }; 353 #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */ 354 /* 355 For some reason, scp->sc_jmpbuf does not work on the RS6000, even though 356 it looks like it should from the include definitions. It is probably 357 some strange interaction with the "POSIX_SOURCE" that we require. 358 */ 359 360 void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp) 361 { 362 int err_ind, j; 363 fp_ctx_t flt_context; 364 PetscErrorCode ierr; 365 366 PetscFunctionBegin; 367 fp_sh_trap_info(scp, &flt_context); 368 369 err_ind = -1; 370 for (j = 0; error_codes[j].code_no; j++) { 371 if (error_codes[j].code_no == flt_context.trap) err_ind = j; 372 } 373 374 if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name); 375 else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap); 376 377 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 378 (void)ierr; 379 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 380 } 381 382 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 383 { 384 PetscFunctionBegin; 385 if (flag == PETSC_FP_TRAP_ON) { 386 signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap); 387 fp_trap(FP_TRAP_SYNC); 388 /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */ 389 fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); 390 } else { 391 signal(SIGFPE, SIG_DFL); 392 fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); 393 fp_trap(FP_TRAP_OFF); 394 } 395 _trapmode = flag; 396 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n")); 397 PetscFunctionReturn(PETSC_SUCCESS); 398 } 399 400 PetscErrorCode PetscDetermineInitialFPTrap(void) 401 { 402 PetscFunctionBegin; 403 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 404 PetscFunctionReturn(PETSC_SUCCESS); 405 } 406 407 /* ------------------------------------------------------------*/ 408 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS) 409 #include <float.h> 410 void PetscDefaultFPTrap(int sig) 411 { 412 PetscErrorCode ierr; 413 414 PetscFunctionBegin; 415 ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 416 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 417 (void)ierr; 418 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 419 } 420 421 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 422 { 423 unsigned int cw; 424 425 PetscFunctionBegin; 426 if (flag == PETSC_FP_TRAP_ON) { 427 /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */ 428 cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW; 429 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 430 } else { 431 cw = 0; 432 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 433 } 434 (void)_controlfp(0, cw); 435 _trapmode = flag; 436 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n")); 437 PetscFunctionReturn(PETSC_SUCCESS); 438 } 439 440 PetscErrorCode PetscDetermineInitialFPTrap(void) 441 { 442 PetscFunctionBegin; 443 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 444 PetscFunctionReturn(PETSC_SUCCESS); 445 } 446 447 /* ------------------------------------------------------------*/ 448 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus) 449 /* 450 C99 style floating point environment. 451 452 Note that C99 merely specifies how to save, restore, and clear the floating 453 point environment as well as defining an enumeration of exception codes. In 454 particular, C99 does not specify how to make floating point exceptions raise 455 a signal. Glibc offers this capability through FE_NOMASK_ENV (or with finer 456 granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK(). 457 */ 458 #include <fenv.h> 459 #if defined(PETSC_HAVE_FE_VALUES) 460 typedef struct { 461 int code; 462 const char *name; 463 } FPNode; 464 static const FPNode error_codes[] = { 465 {FE_DIVBYZERO, "divide by zero" }, 466 {FE_INEXACT, "inexact floating point result" }, 467 {FE_INVALID, "invalid floating point arguments (domain error)"}, 468 {FE_OVERFLOW, "floating point overflow" }, 469 {FE_UNDERFLOW, "floating point underflow" }, 470 {0, "unknown error" } 471 }; 472 #endif 473 474 void PetscDefaultFPTrap(int sig) 475 { 476 #if defined(PETSC_HAVE_FE_VALUES) 477 const FPNode *node; 478 int code; 479 PetscBool matched = PETSC_FALSE; 480 #endif 481 PetscErrorCode ierr; 482 483 PetscFunctionBegin; 484 /* Note: While it is possible for the exception state to be preserved by the 485 * kernel, this seems to be rare which makes the following flag testing almost 486 * useless. But on a system where the flags can be preserved, it would provide 487 * more detail. 488 */ 489 #if defined(PETSC_HAVE_FE_VALUES) 490 code = fetestexcept(FE_ALL_EXCEPT); 491 for (node = &error_codes[0]; node->code; node++) { 492 if (code & node->code) { 493 matched = PETSC_TRUE; 494 ierr = (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name); 495 code &= ~node->code; /* Unset this flag since it has been processed */ 496 } 497 } 498 if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */ 499 ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n"); 500 ierr = (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger. When the\n"); 501 ierr = (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT); 502 ierr = (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n"); 503 ierr = (*PetscErrorPrintf)("FE_INVALID=0x%x FE_DIVBYZERO=0x%x FE_OVERFLOW=0x%x FE_UNDERFLOW=0x%x FE_INEXACT=0x%x\n", FE_INVALID, FE_DIVBYZERO, FE_OVERFLOW, FE_UNDERFLOW, FE_INEXACT); 504 } 505 #else 506 ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n"); 507 #endif 508 509 ierr = (*PetscErrorPrintf)("Try option -start_in_debugger\n"); 510 #if PetscDefined(USE_DEBUG) 511 #if !PetscDefined(HAVE_THREADSAFETY) 512 ierr = (*PetscErrorPrintf)("likely location of problem given in stack below\n"); 513 ierr = (*PetscErrorPrintf)("--------------------- Stack Frames ------------------------------------\n"); 514 ierr = PetscStackView(PETSC_STDOUT); 515 #endif 516 #else 517 ierr = (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n"); 518 ierr = (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n"); 519 #endif 520 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error"); 521 (void)ierr; 522 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 523 } 524 525 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 526 { 527 PetscFunctionBegin; 528 if (flag == PETSC_FP_TRAP_ON) { 529 /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */ 530 PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags"); 531 #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES) 532 /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */ 533 /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */ 534 /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */ 535 PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions"); 536 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n")); 537 #elif defined PETSC_HAVE_XMMINTRIN_H 538 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO); 539 /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */ 540 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW); 541 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID); 542 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n")); 543 #else 544 /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */ 545 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n")); 546 #endif 547 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 548 } else { 549 PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions"); 550 /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */ 551 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 552 } 553 _trapmode = flag; 554 PetscFunctionReturn(PETSC_SUCCESS); 555 } 556 557 PetscErrorCode PetscDetermineInitialFPTrap(void) 558 { 559 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H 560 unsigned int flags; 561 #endif 562 563 PetscFunctionBegin; 564 #if defined(FE_NOMASK_ENV) 565 flags = fegetexcept(); 566 if (flags & FE_DIVBYZERO) { 567 #elif defined PETSC_HAVE_XMMINTRIN_H 568 flags = _MM_GET_EXCEPTION_MASK(); 569 if (!(flags & _MM_MASK_DIV_ZERO)) { 570 #else 571 PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n")); 572 PetscFunctionReturn(PETSC_SUCCESS); 573 #endif 574 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H 575 _trapmode = PETSC_FP_TRAP_ON; 576 PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags)); 577 } else { 578 _trapmode = PETSC_FP_TRAP_OFF; 579 PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags)); 580 } 581 PetscFunctionReturn(PETSC_SUCCESS); 582 #endif 583 } 584 585 /* ------------------------------------------------------------*/ 586 #elif defined(PETSC_HAVE_IEEEFP_H) 587 #include <ieeefp.h> 588 void PetscDefaultFPTrap(int sig) 589 { 590 PetscErrorCode ierr; 591 592 PetscFunctionBegin; 593 ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 594 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 595 (void)ierr; 596 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 597 } 598 599 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 600 { 601 PetscFunctionBegin; 602 if (flag == PETSC_FP_TRAP_ON) { 603 #if defined(PETSC_HAVE_FPRESETSTICKY) 604 fpresetsticky(fpgetsticky()); 605 #elif defined(PETSC_HAVE_FPSETSTICKY) 606 fpsetsticky(fpgetsticky()); 607 #endif 608 fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL); 609 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 610 } else { 611 #if defined(PETSC_HAVE_FPRESETSTICKY) 612 fpresetsticky(fpgetsticky()); 613 #elif defined(PETSC_HAVE_FPSETSTICKY) 614 fpsetsticky(fpgetsticky()); 615 #endif 616 fpsetmask(0); 617 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 618 } 619 _trapmode = flag; 620 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n")); 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 PetscErrorCode PetscDetermineInitialFPTrap(void) 625 { 626 PetscFunctionBegin; 627 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 628 PetscFunctionReturn(PETSC_SUCCESS); 629 } 630 631 /* -------------------------Default -----------------------------------*/ 632 #else 633 634 void PetscDefaultFPTrap(int sig) 635 { 636 PetscErrorCode ierr; 637 638 PetscFunctionBegin; 639 ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 640 ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 641 (void)ierr; 642 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 643 } 644 645 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 646 { 647 PetscFunctionBegin; 648 if (flag == PETSC_FP_TRAP_ON) { 649 if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n")); 650 } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n")); 651 652 _trapmode = flag; 653 PetscCall(PetscInfo(NULL, "Using default FPTRAP\n")); 654 PetscFunctionReturn(PETSC_SUCCESS); 655 } 656 657 PetscErrorCode PetscDetermineInitialFPTrap(void) 658 { 659 PetscFunctionBegin; 660 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 661 PetscFunctionReturn(PETSC_SUCCESS); 662 } 663 #endif 664