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