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