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