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