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