1 2 /* 3 * IEEE error handler for all machines. Since each machine has 4 * enough slight differences we have completely separate codes for each one. 5 * 6 */ 7 8 /* 9 This feature test macro provides FE_NOMASK_ENV on GNU. It must be defined 10 at the top of the file because other headers may pull in fenv.h even when 11 not strictly necessary. Strictly speaking, we could include ONLY petscconf.h, 12 check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such 13 shenanigans ought to be unnecessary. 14 */ 15 #if !defined(_GNU_SOURCE) 16 #define _GNU_SOURCE 17 #endif 18 19 #include <petscsys.h> /*I "petscsys.h" I*/ 20 #include <signal.h> 21 #if defined(PETSC_HAVE_STDLIB_H) 22 #include <stdlib.h> 23 #endif 24 25 struct PetscFPTrapLink { 26 PetscFPTrap trapmode; 27 struct PetscFPTrapLink *next; 28 }; 29 static PetscFPTrap _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode */ 30 static struct PetscFPTrapLink *_trapstack; /* Any pushed states of _trapmode */ 31 32 #undef __FUNCT__ 33 #define __FUNCT__ "PetscFPTrapPush" 34 /*@ 35 PetscFPTrapPush - push a floating point trapping mode, to be restored using PetscFPTrapPop() 36 37 Not Collective 38 39 Input Arguments: 40 . trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF 41 42 Level: advanced 43 44 .seealso: PetscFPTrapPop(), PetscSetFPTrap() 45 @*/ 46 PetscErrorCode PetscFPTrapPush(PetscFPTrap trap) 47 { 48 PetscErrorCode ierr; 49 struct PetscFPTrapLink *link; 50 51 PetscFunctionBegin; 52 ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr); 53 link->trapmode = _trapmode; 54 link->next = _trapstack; 55 _trapstack = link; 56 if (trap != _trapmode) {ierr = PetscSetFPTrap(trap);CHKERRQ(ierr);} 57 PetscFunctionReturn(0); 58 } 59 60 #undef __FUNCT__ 61 #define __FUNCT__ "PetscFPTrapPop" 62 /*@ 63 PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop() 64 65 Not Collective 66 67 Level: advanced 68 69 .seealso: PetscFPTrapPush(), PetscSetFPTrap() 70 @*/ 71 PetscErrorCode PetscFPTrapPop(void) 72 { 73 PetscErrorCode ierr; 74 struct PetscFPTrapLink *link; 75 76 PetscFunctionBegin; 77 if (_trapstack->trapmode != _trapmode) {ierr = PetscSetFPTrap(_trapstack->trapmode);CHKERRQ(ierr);} 78 link = _trapstack; 79 _trapstack = _trapstack->next; 80 ierr = PetscFree(link);CHKERRQ(ierr); 81 PetscFunctionReturn(0); 82 } 83 84 /*--------------------------------------- ---------------------------------------------------*/ 85 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP) 86 #include <floatingpoint.h> 87 88 EXTERN_C_BEGIN 89 PetscErrorCode ieee_flags(char*,char*,char*,char**); 90 PetscErrorCode ieee_handler(char *,char *,sigfpe_handler_type(int,int,struct sigcontext*,char *)); 91 EXTERN_C_END 92 93 static struct { int code_no; char *name; } error_codes[] = { 94 { FPE_INTDIV_TRAP ,"integer divide" }, 95 { FPE_FLTOPERR_TRAP ,"IEEE operand error" }, 96 { FPE_FLTOVF_TRAP ,"floating point overflow" }, 97 { FPE_FLTUND_TRAP ,"floating point underflow" }, 98 { FPE_FLTDIV_TRAP ,"floating pointing divide" }, 99 { FPE_FLTINEX_TRAP ,"inexact floating point result" }, 100 { 0 ,"unknown error" } 101 }; 102 #define SIGPC(scp) (scp->sc_pc) 103 104 #undef __FUNCT__ 105 #define __FUNCT__ "PetscDefaultFPTrap" 106 sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr) 107 { 108 PetscErrorCode ierr; 109 int err_ind = -1,j; 110 111 PetscFunctionBegin; 112 for (j = 0 ; error_codes[j].code_no ; j++) { 113 if (error_codes[j].code_no == code) err_ind = j; 114 } 115 116 if (err_ind >= 0) { 117 (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp)); 118 } else { 119 (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp)); 120 } 121 ierr = PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error"); 122 MPI_Abort(PETSC_COMM_WORLD,0); 123 PetscFunctionReturn(0); 124 } 125 126 #undef __FUNCT__ 127 #define __FUNCT__ "PetscSetFPTrap" 128 /*@ 129 PetscSetFPTrap - Enables traps/exceptions on common floating point errors. 130 This option may not work on certain machines. 131 132 Not Collective 133 134 Input Parameters: 135 . flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF. 136 137 Options Database Keys: 138 . -fp_trap - Activates floating point trapping 139 140 Level: advanced 141 142 Description: 143 On systems that support it, this routine causes floating point 144 overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to 145 cause a message to be printed and the program to exit. 146 147 Note: 148 On many common systems including x86 and x86-64 Linux, the floating 149 point exception state is not preserved from the location where the trap 150 occurred through to the signal handler. In this case, the signal handler 151 will just say that an unknown floating point exception occurred and which 152 function it occurred in. If you run with -fp_trap in a debugger, it will 153 break on the line where the error occurred. You can check which 154 exception occurred using fetestexcept(FE_ALL_EXCEPT). See fenv.h 155 (usually at /usr/include/bits/fenv.h) for the enum values on your system. 156 157 Caution: 158 On certain machines, in particular the IBM rs6000, floating point 159 trapping is VERY slow! 160 161 Concepts: floating point exceptions^trapping 162 Concepts: divide by zero 163 164 .seealso: PetscFPTrapPush(), PetscFPTrapPop() 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 if (ieee_handler("set","common",PetscDefaultFPTrap)) { 175 /* 176 To trap more fp exceptions, including undrflow, change the above line to 177 if (ieee_handler("set","all",PetscDefaultFPTrap)) { 178 */ 179 (*PetscErrorPrintf)("Can't set floatingpoint handler\n"); 180 } 181 } else { 182 if (ieee_handler("clear","common",PetscDefaultFPTrap)) { 183 (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 184 } 185 } 186 _trapmode = flag; 187 PetscFunctionReturn(0); 188 } 189 190 /* -------------------------------------------------------------------------------------------*/ 191 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP) 192 #include <sunmath.h> 193 #include <floatingpoint.h> 194 #include <siginfo.h> 195 #include <ucontext.h> 196 197 static struct { int code_no; char *name; } error_codes[] = { 198 { FPE_FLTINV,"invalid floating point operand"}, 199 { FPE_FLTRES,"inexact floating point result"}, 200 { FPE_FLTDIV,"division-by-zero"}, 201 { FPE_FLTUND,"floating point underflow"}, 202 { FPE_FLTOVF,"floating point overflow"}, 203 { 0, "unknown error"} 204 }; 205 #define SIGPC(scp) (scp->si_addr) 206 207 #undef __FUNCT__ 208 #define __FUNCT__ "PetscDefaultFPTrap" 209 void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap) 210 { 211 int err_ind,j,code = scp->si_code; 212 PetscErrorCode ierr; 213 214 PetscFunctionBegin; 215 err_ind = -1 ; 216 for (j = 0 ; error_codes[j].code_no ; j++) { 217 if (error_codes[j].code_no == code) err_ind = j; 218 } 219 220 if (err_ind >= 0) { 221 (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp)); 222 } else { 223 (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp)); 224 } 225 ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error"); 226 MPI_Abort(PETSC_COMM_WORLD,0); 227 } 228 229 #undef __FUNCT__ 230 #define __FUNCT__ "PetscSetFPTrap" 231 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 232 { 233 char *out; 234 235 PetscFunctionBegin; 236 /* Clear accumulated exceptions. Used to suppress meaningless messages from f77 programs */ 237 (void) ieee_flags("clear","exception","all",&out); 238 if (flag == PETSC_FP_TRAP_ON) { 239 if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap)) { 240 (*PetscErrorPrintf)("Can't set floating point handler\n"); 241 } 242 } else { 243 if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) { 244 (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 245 } 246 } 247 _trapmode = flag; 248 PetscFunctionReturn(0); 249 } 250 251 /* ------------------------------------------------------------------------------------------*/ 252 253 #elif defined (PETSC_HAVE_IRIX_STYLE_FPTRAP) 254 #include <sigfpe.h> 255 static struct { int code_no; char *name; } error_codes[] = { 256 { _INVALID ,"IEEE operand error" }, 257 { _OVERFL ,"floating point overflow" }, 258 { _UNDERFL ,"floating point underflow" }, 259 { _DIVZERO ,"floating point divide" }, 260 { 0 ,"unknown error" } 261 } ; 262 #undef __FUNCT__ 263 #define __FUNCT__ "PetscDefaultFPTrap" 264 void PetscDefaultFPTrap(unsigned exception[],int val[]) 265 { 266 int err_ind,j,code; 267 268 PetscFunctionBegin; 269 code = exception[0]; 270 err_ind = -1 ; 271 for (j = 0 ; error_codes[j].code_no ; j++) { 272 if (error_codes[j].code_no == code) err_ind = j; 273 } 274 if (err_ind >= 0) { 275 (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name); 276 } else { 277 (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code); 278 } 279 PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error"); 280 MPI_Abort(PETSC_COMM_WORLD,0); 281 } 282 283 #undef __FUNCT__ 284 #define __FUNCT__ "PetscSetFPTrap" 285 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) 286 { 287 PetscFunctionBegin; 288 if (flag == PETSC_FP_TRAP_ON) { 289 handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0); 290 } else { 291 handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0); 292 } 293 _trapmode = flag; 294 PetscFunctionReturn(0); 295 } 296 /*----------------------------------------------- --------------------------------------------*/ 297 /* In "fast" mode, floating point traps are imprecise and ignored. 298 This is the reason for the fptrap(FP_TRAP_SYNC) call */ 299 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP) 300 struct sigcontext; 301 #include <fpxcp.h> 302 #include <fptrap.h> 303 #include <stdlib.h> 304 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000) 305 #define FPE_FLTOVF_TRAP (fptrap_t)(0x10000000) 306 #define FPE_FLTUND_TRAP (fptrap_t)(0x08000000) 307 #define FPE_FLTDIV_TRAP (fptrap_t)(0x04000000) 308 #define FPE_FLTINEX_TRAP (fptrap_t)(0x02000000) 309 310 static struct { int code_no; char *name; } error_codes[] = { 311 {FPE_FLTOPERR_TRAP ,"IEEE operand error" }, 312 { FPE_FLTOVF_TRAP ,"floating point overflow" }, 313 { FPE_FLTUND_TRAP ,"floating point underflow" }, 314 { FPE_FLTDIV_TRAP ,"floating point divide" }, 315 { FPE_FLTINEX_TRAP ,"inexact floating point result" }, 316 { 0 ,"unknown error" } 317 } ; 318 #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */ 319 /* 320 For some reason, scp->sc_jmpbuf does not work on the RS6000, even though 321 it looks like it should from the include definitions. It is probably 322 some strange interaction with the "POSIX_SOURCE" that we require. 323 */ 324 325 #undef __FUNCT__ 326 #define __FUNCT__ "PetscDefaultFPTrap" 327 void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp) 328 { 329 PetscErrorCode ierr; 330 int err_ind,j; 331 fp_ctx_t flt_context; 332 333 PetscFunctionBegin; 334 fp_sh_trap_info(scp,&flt_context); 335 336 err_ind = -1 ; 337 for (j = 0 ; error_codes[j].code_no ; j++) { 338 if (error_codes[j].code_no == flt_context.trap) err_ind = j; 339 } 340 341 if (err_ind >= 0) { 342 (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name); 343 } else { 344 (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap); 345 } 346 ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error"); 347 MPI_Abort(PETSC_COMM_WORLD,0); 348 } 349 350 #undef __FUNCT__ 351 #define __FUNCT__ "PetscSetFPTrap" 352 PetscErrorCode PetscSetFPTrap(PetscFPTrap on) 353 { 354 PetscFunctionBegin; 355 if (on == PETSC_FP_TRAP_ON) { 356 signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap); 357 fp_trap(FP_TRAP_SYNC); 358 fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); 359 /* fp_enable(mask) for individual traps. Values are: 360 TRP_INVALID 361 TRP_DIV_BY_ZERO 362 TRP_OVERFLOW 363 TRP_UNDERFLOW 364 TRP_INEXACT 365 Can OR then together. 366 fp_enable_all(); for all traps. 367 */ 368 } else { 369 signal(SIGFPE,SIG_DFL); 370 fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); 371 fp_trap(FP_TRAP_OFF); 372 } 373 _trapmode = on; 374 PetscFunctionReturn(0); 375 } 376 377 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus) 378 /* 379 C99 style floating point environment. 380 381 Note that C99 merely specifies how to save, restore, and clear the floating 382 point environment as well as defining an enumeration of exception codes. In 383 particular, C99 does not specify how to make floating point exceptions raise 384 a signal. Glibc offers this capability through FE_NOMASK_ENV (or with finer 385 granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK(). 386 */ 387 #include <fenv.h> 388 typedef struct {int code; const char *name;} FPNode; 389 static const FPNode error_codes[] = { 390 {FE_DIVBYZERO,"divide by zero"}, 391 {FE_INEXACT, "inexact floating point result"}, 392 {FE_INVALID, "invalid floating point arguments (domain error)"}, 393 {FE_OVERFLOW, "floating point overflow"}, 394 {FE_UNDERFLOW,"floating point underflow"}, 395 {0 ,"unknown error"} 396 }; 397 EXTERN_C_BEGIN 398 #undef __FUNCT__ 399 #define __FUNCT__ "PetscDefaultFPTrap" 400 void PetscDefaultFPTrap(int sig) 401 { 402 const FPNode *node; 403 int code; 404 PetscBool matched = PETSC_FALSE; 405 406 PetscFunctionBegin; 407 /* Note: While it is possible for the exception state to be preserved by the 408 * kernel, this seems to be rare which makes the following flag testing almost 409 * useless. But on a system where the flags can be preserved, it would provide 410 * more detail. 411 */ 412 code = fetestexcept(FE_ALL_EXCEPT); 413 for (node=&error_codes[0]; node->code; node++) { 414 if (code & node->code) { 415 matched = PETSC_TRUE; 416 (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name); 417 code &= ~node->code; /* Unset this flag since it has been processed */ 418 } 419 } 420 if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */ 421 (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n"); 422 (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger. When the\n"); 423 (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT); 424 (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n"); 425 (*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); 426 } 427 428 (*PetscErrorPrintf)("Try option -start_in_debugger\n"); 429 #if defined(PETSC_USE_DEBUG) 430 if (!PetscStackActive) { 431 (*PetscErrorPrintf)(" or try option -log_stack\n"); 432 } else { 433 (*PetscErrorPrintf)("likely location of problem given in stack below\n"); 434 (*PetscErrorPrintf)("--------------------- Stack Frames ------------------------------------\n"); 435 PetscStackView(PETSC_STDOUT); 436 } 437 #endif 438 #if !defined(PETSC_USE_DEBUG) 439 (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n"); 440 (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n"); 441 #endif 442 PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error"); 443 MPI_Abort(PETSC_COMM_WORLD,0); 444 } 445 EXTERN_C_END 446 447 #undef __FUNCT__ 448 #define __FUNCT__ "PetscSetFPTrap" 449 PetscErrorCode PetscSetFPTrap(PetscFPTrap on) 450 { 451 PetscFunctionBegin; 452 if (on == PETSC_FP_TRAP_ON) { 453 /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */ 454 if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n"); 455 #if defined FE_NOMASK_ENV 456 /* We could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */ 457 if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n"); 458 #elif defined PETSC_HAVE_XMMINTRIN_H 459 _MM_SET_EXCEPTION_MASK(_MM_MASK_INEXACT); 460 #else 461 /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */ 462 #endif 463 if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n"); 464 } else { 465 if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions"); 466 if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n"); 467 } 468 _trapmode = on; 469 PetscFunctionReturn(0); 470 } 471 472 /* -------------------------Default -----------------------------------*/ 473 #else 474 EXTERN_C_BEGIN 475 #undef __FUNCT__ 476 #define __FUNCT__ "PetscDefaultFPTrap" 477 void PetscDefaultFPTrap(int sig) 478 { 479 PetscFunctionBegin; 480 (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 481 PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error"); 482 MPI_Abort(PETSC_COMM_WORLD,0); 483 } 484 EXTERN_C_END 485 #undef __FUNCT__ 486 #define __FUNCT__ "PetscSetFPTrap" 487 PetscErrorCode PetscSetFPTrap(PetscFPTrap on) 488 { 489 PetscFunctionBegin; 490 if (on == PETSC_FP_TRAP_ON) { 491 if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) { 492 (*PetscErrorPrintf)("Can't set floatingpoint handler\n"); 493 } 494 } else { 495 if (SIG_ERR == signal(SIGFPE,SIG_DFL)) { 496 (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 497 } 498 } 499 _trapmode = on; 500 PetscFunctionReturn(0); 501 } 502 #endif 503 504 505 506