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