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