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