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