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