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