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