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