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