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