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