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