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