xref: /petsc/src/sys/error/fp.c (revision 2fe279fdf3e687a416e4eadb7d3c7a82d60442c6)
17d0a6c19SBarry Smith 
2e5c89e4eSSatish Balay /*
30e3d61c9SBarry Smith    IEEE error handler for all machines. Since each OS has
40e3d61c9SBarry Smith    enough slight differences we have completely separate codes for each one.
5e5c89e4eSSatish Balay */
6b014e56cSJed Brown 
7b014e56cSJed Brown /*
8b014e56cSJed Brown   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
9b014e56cSJed Brown   at the top of the file because other headers may pull in fenv.h even when
10b014e56cSJed Brown   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
11b014e56cSJed Brown   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
12b014e56cSJed Brown   shenanigans ought to be unnecessary.
13b014e56cSJed Brown */
14519f805aSKarl Rupp #if !defined(_GNU_SOURCE)
15b014e56cSJed Brown   #define _GNU_SOURCE
1676a6984eSJed Brown #endif
17b014e56cSJed Brown 
1827104ee2SJacob Faibussowitsch #include <petsc/private/petscimpl.h> /*I  "petscsys.h"  I*/
19e5c89e4eSSatish Balay #include <signal.h>
20e5c89e4eSSatish Balay 
21670f3ff9SJed Brown struct PetscFPTrapLink {
22670f3ff9SJed Brown   PetscFPTrap             trapmode;
23670f3ff9SJed Brown   struct PetscFPTrapLink *next;
24670f3ff9SJed Brown };
25aba4c478SBarry Smith static PetscFPTrap             _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */
26670f3ff9SJed Brown static struct PetscFPTrapLink *_trapstack;                    /* Any pushed states of _trapmode */
27670f3ff9SJed Brown 
28670f3ff9SJed Brown /*@
29811af0c4SBarry Smith    PetscFPTrapPush - push a floating point trapping mode, restored using `PetscFPTrapPop()`
30670f3ff9SJed Brown 
31670f3ff9SJed Brown    Not Collective
32670f3ff9SJed Brown 
334165533cSJose E. Roman    Input Parameter:
34811af0c4SBarry Smith .    trap - `PETSC_FP_TRAP_ON` or `PETSC_FP_TRAP_OFF` or any of the values passable to `PetscSetFPTrap()`
35670f3ff9SJed Brown 
36670f3ff9SJed Brown    Level: advanced
37670f3ff9SJed Brown 
38cc9df77eSBarry Smith    Notes:
39cc9df77eSBarry Smith      This only changes the trapping if the new mode is different than the current mode.
40cc9df77eSBarry Smith 
41cc9df77eSBarry Smith      This routine is called to turn off trapping for certain LAPACK routines that assume that dividing
42cc9df77eSBarry Smith      by zero is acceptable. In particular the routine ieeeck().
43cc9df77eSBarry Smith 
44cc9df77eSBarry Smith      Most systems by default have all trapping turned off, but certain Fortran compilers have
45cc9df77eSBarry Smith      link flags that turn on trapping before the program begins.
46cc9df77eSBarry Smith $       gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal
47cc9df77eSBarry Smith $       ifort -fpe0
48cc9df77eSBarry Smith 
49db781477SPatrick Sanan .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
50670f3ff9SJed Brown @*/
51d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
52d71ae5a4SJacob Faibussowitsch {
53670f3ff9SJed Brown   struct PetscFPTrapLink *link;
54670f3ff9SJed Brown 
55670f3ff9SJed Brown   PetscFunctionBegin;
569566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
571f006be4SPierre Jolivet #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
58ed6c4ed2SJacob Faibussowitsch   PetscPragmaOMP(critical)
591f006be4SPierre Jolivet #endif
601f006be4SPierre Jolivet   {
61670f3ff9SJed Brown     link->trapmode = _trapmode;
62670f3ff9SJed Brown     link->next     = _trapstack;
63670f3ff9SJed Brown     _trapstack     = link;
641f006be4SPierre Jolivet   }
659566063dSJacob Faibussowitsch   if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap));
663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
67670f3ff9SJed Brown }
68670f3ff9SJed Brown 
69670f3ff9SJed Brown /*@
70811af0c4SBarry Smith    PetscFPTrapPop - push a floating point trapping mode, to be restored using `PetscFPTrapPop()`
71670f3ff9SJed Brown 
72670f3ff9SJed Brown    Not Collective
73670f3ff9SJed Brown 
74670f3ff9SJed Brown    Level: advanced
75670f3ff9SJed Brown 
76db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()`
77670f3ff9SJed Brown @*/
78d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFPTrapPop(void)
79d71ae5a4SJacob Faibussowitsch {
80670f3ff9SJed Brown   struct PetscFPTrapLink *link;
81670f3ff9SJed Brown 
82670f3ff9SJed Brown   PetscFunctionBegin;
839566063dSJacob Faibussowitsch   if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode));
841f006be4SPierre Jolivet #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP)
85ed6c4ed2SJacob Faibussowitsch   PetscPragmaOMP(critical)
861f006be4SPierre Jolivet #endif
871f006be4SPierre Jolivet   {
88670f3ff9SJed Brown     link       = _trapstack;
89670f3ff9SJed Brown     _trapstack = _trapstack->next;
901f006be4SPierre Jolivet   }
919566063dSJacob Faibussowitsch   PetscCall(PetscFree(link));
923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
93670f3ff9SJed Brown }
94670f3ff9SJed Brown 
95e5c89e4eSSatish Balay /*--------------------------------------- ---------------------------------------------------*/
96e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
97e5c89e4eSSatish Balay   #include <floatingpoint.h>
98e5c89e4eSSatish Balay 
998cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **);
1008cc058d9SJed Brown PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *));
101e5c89e4eSSatish Balay 
1029371c9d4SSatish Balay static struct {
1039371c9d4SSatish Balay   int   code_no;
1049371c9d4SSatish Balay   char *name;
1059371c9d4SSatish Balay } error_codes[] = {
106e5c89e4eSSatish Balay   {FPE_INTDIV_TRAP,   "integer divide"               },
107e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
108e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
109e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
110e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating pointing divide"     },
111e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
112e5c89e4eSSatish Balay   {0,                 "unknown error"                }
113e5c89e4eSSatish Balay };
114e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->sc_pc)
115e5c89e4eSSatish Balay 
116cf0818bdSBarry Smith /* this function gets called if a trap has occurred and been caught */
117d71ae5a4SJacob Faibussowitsch sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr)
118d71ae5a4SJacob Faibussowitsch {
1195f80ce2aSJacob Faibussowitsch   int            err_ind = -1;
1203ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
121e5c89e4eSSatish Balay 
122e5c89e4eSSatish Balay   PetscFunctionBegin;
1235f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
124e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
125e5c89e4eSSatish Balay   }
126e5c89e4eSSatish Balay 
1273ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
1283ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
129a297a907SKarl Rupp 
1303ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
1313ba16761SJacob Faibussowitsch   (void)ierr;
13241e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
1333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
134e5c89e4eSSatish Balay }
135e5c89e4eSSatish Balay 
136e30d2299SSatish Balay /*@
137cf0818bdSBarry Smith    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
138cf0818bdSBarry Smith    subset of exceptions may be trapable.
139e5c89e4eSSatish Balay 
140e5c89e4eSSatish Balay    Not Collective
141e5c89e4eSSatish Balay 
142*2fe279fdSBarry Smith    Input Parameter:
143cf0818bdSBarry Smith .  flag - values are
144cf0818bdSBarry Smith .vb
145cf0818bdSBarry Smith     PETSC_FP_TRAP_OFF   - do not trap any exceptions
146cf0818bdSBarry Smith     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
147cf0818bdSBarry Smith     PETSC_FP_TRAP_INDIV - integer divide by zero
148cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
149cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOVF - overflow
150cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
151cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
152cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTINEX - inexact floating point result
153cf0818bdSBarry Smith .ve
154e5c89e4eSSatish Balay 
155*2fe279fdSBarry Smith    Options Database Key:
156cf0818bdSBarry Smith .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
157e5c89e4eSSatish Balay 
158e5c89e4eSSatish Balay    Level: advanced
159e5c89e4eSSatish Balay 
160cf0818bdSBarry Smith    Notes:
161811af0c4SBarry Smith    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
162cf0818bdSBarry Smith 
163cf0818bdSBarry Smith    The values are bit values and may be |ed together in the function call
164cf0818bdSBarry Smith 
165cf0818bdSBarry Smith    On systems that support it this routine causes floating point
166cf0818bdSBarry Smith    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
167e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
168e5c89e4eSSatish Balay 
169cc9df77eSBarry Smith    On many common systems, the floating
1707d125cddSJed Brown    point exception state is not preserved from the location where the trap
1717d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1727d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1737d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
174cc9df77eSBarry Smith    break on the line where the error occurred.  On systems that support C99
175cc9df77eSBarry Smith    floating point exception handling You can check which
1767d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1777d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1787d125cddSJed Brown 
179db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
180e5c89e4eSSatish Balay @*/
181d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
182d71ae5a4SJacob Faibussowitsch {
183e5c89e4eSSatish Balay   char *out;
184e5c89e4eSSatish Balay 
185e5c89e4eSSatish Balay   PetscFunctionBegin;
186e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
187e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
188bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
189e5c89e4eSSatish Balay     /*
190a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
191e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
192e5c89e4eSSatish Balay     */
193a297a907SKarl Rupp     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
194a297a907SKarl Rupp   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
195a297a907SKarl Rupp 
196670f3ff9SJed Brown   _trapmode = flag;
197bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
199e5c89e4eSSatish Balay }
200e5c89e4eSSatish Balay 
201cc9df77eSBarry Smith /*@
202811af0c4SBarry Smith    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
203cc9df77eSBarry Smith 
204cc9df77eSBarry Smith    Not Collective
205cc9df77eSBarry Smith 
206811af0c4SBarry Smith    Note:
207cc9df77eSBarry Smith       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.
208cc9df77eSBarry Smith 
209ee300463SSatish Balay    Level: advanced
210cc9df77eSBarry Smith 
211db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
212cc9df77eSBarry Smith @*/
213d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
214d71ae5a4SJacob Faibussowitsch {
215cc9df77eSBarry Smith   PetscFunctionBegin;
2169566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
218cc9df77eSBarry Smith }
219cc9df77eSBarry Smith 
220e5c89e4eSSatish Balay /* -------------------------------------------------------------------------------------------*/
221e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
222e5c89e4eSSatish Balay   #include <sunmath.h>
223e5c89e4eSSatish Balay   #include <floatingpoint.h>
224e5c89e4eSSatish Balay   #include <siginfo.h>
225e5c89e4eSSatish Balay   #include <ucontext.h>
226e5c89e4eSSatish Balay 
2279371c9d4SSatish Balay static struct {
2289371c9d4SSatish Balay   int   code_no;
2299371c9d4SSatish Balay   char *name;
2309371c9d4SSatish Balay } error_codes[] = {
231e5c89e4eSSatish Balay   {FPE_FLTINV, "invalid floating point operand"},
232e5c89e4eSSatish Balay   {FPE_FLTRES, "inexact floating point result" },
233e5c89e4eSSatish Balay   {FPE_FLTDIV, "division-by-zero"              },
234e5c89e4eSSatish Balay   {FPE_FLTUND, "floating point underflow"      },
235e5c89e4eSSatish Balay   {FPE_FLTOVF, "floating point overflow"       },
236e5c89e4eSSatish Balay   {0,          "unknown error"                 }
237e5c89e4eSSatish Balay };
238e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->si_addr)
239e5c89e4eSSatish Balay 
240d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
241d71ae5a4SJacob Faibussowitsch {
2425f80ce2aSJacob Faibussowitsch   int            err_ind = -1, code = scp->si_code;
2433ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
244e5c89e4eSSatish Balay 
245e5c89e4eSSatish Balay   PetscFunctionBegin;
2465f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
247e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
248e5c89e4eSSatish Balay   }
249e5c89e4eSSatish Balay 
2503ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
2513ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
252a297a907SKarl Rupp 
2533ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
2543ba16761SJacob Faibussowitsch   (void)ierr;
25541e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
256e5c89e4eSSatish Balay }
257e5c89e4eSSatish Balay 
258d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
259d71ae5a4SJacob Faibussowitsch {
260e5c89e4eSSatish Balay   char *out;
261e5c89e4eSSatish Balay 
262e5c89e4eSSatish Balay   PetscFunctionBegin;
263e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
264e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
265e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
266a297a907SKarl Rupp     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
267cc9df77eSBarry Smith   } else {
268cc9df77eSBarry Smith     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
269cc9df77eSBarry Smith   }
270670f3ff9SJed Brown   _trapmode = flag;
271bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
2723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
273e5c89e4eSSatish Balay }
274e5c89e4eSSatish Balay 
275d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
276d71ae5a4SJacob Faibussowitsch {
277cc9df77eSBarry Smith   PetscFunctionBegin;
2789566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280cc9df77eSBarry Smith }
281cc9df77eSBarry Smith 
282cc9df77eSBarry Smith /* ------------------------------------------------------------------------------------------*/
283e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
284e5c89e4eSSatish Balay   #include <sigfpe.h>
2859371c9d4SSatish Balay static struct {
2869371c9d4SSatish Balay   int   code_no;
2879371c9d4SSatish Balay   char *name;
2889371c9d4SSatish Balay } error_codes[] = {
289e5c89e4eSSatish Balay   {_INVALID, "IEEE operand error"      },
290e5c89e4eSSatish Balay   {_OVERFL,  "floating point overflow" },
291e5c89e4eSSatish Balay   {_UNDERFL, "floating point underflow"},
292e5c89e4eSSatish Balay   {_DIVZERO, "floating point divide"   },
293e5c89e4eSSatish Balay   {0,        "unknown error"           }
294e5c89e4eSSatish Balay };
295d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(unsigned exception[], int val[])
296d71ae5a4SJacob Faibussowitsch {
2975f80ce2aSJacob Faibussowitsch   int            err_ind = -1, code = exception[0];
2983ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
299e5c89e4eSSatish Balay 
300e5c89e4eSSatish Balay   PetscFunctionBegin;
3015f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
302e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
303e5c89e4eSSatish Balay   }
3043ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
3053ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
306a297a907SKarl Rupp 
3073ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
3083ba16761SJacob Faibussowitsch   (void)ierr;
30941e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
310e5c89e4eSSatish Balay }
311e5c89e4eSSatish Balay 
312d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
313d71ae5a4SJacob Faibussowitsch {
314e5c89e4eSSatish Balay   PetscFunctionBegin;
315bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
316cc9df77eSBarry Smith   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
317670f3ff9SJed Brown   _trapmode = flag;
318bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
3193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
320cc9df77eSBarry Smith }
321cc9df77eSBarry Smith 
322d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
323d71ae5a4SJacob Faibussowitsch {
324cc9df77eSBarry Smith   PetscFunctionBegin;
3259566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
3263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
327cc9df77eSBarry Smith }
328cc9df77eSBarry Smith 
329cc9df77eSBarry Smith /*----------------------------------------------- --------------------------------------------*/
330cc9df77eSBarry Smith #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
331e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
332e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
333e5c89e4eSSatish Balay struct sigcontext;
334e5c89e4eSSatish Balay   #include <fpxcp.h>
335e5c89e4eSSatish Balay   #include <fptrap.h>
336e5c89e4eSSatish Balay   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
337e5c89e4eSSatish Balay   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
338e5c89e4eSSatish Balay   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
339e5c89e4eSSatish Balay   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
340e5c89e4eSSatish Balay   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
341e5c89e4eSSatish Balay 
3429371c9d4SSatish Balay static struct {
3439371c9d4SSatish Balay   int   code_no;
3449371c9d4SSatish Balay   char *name;
3459371c9d4SSatish Balay } error_codes[] = {
346e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
347e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
348e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
349e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating point divide"        },
350e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
351bd2b07b1SBarry Smith   < {0,                 "unknown error"                }
352e5c89e4eSSatish Balay };
353e5c89e4eSSatish Balay   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
354e5c89e4eSSatish Balay /*
355e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
356e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
357e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
358e5c89e4eSSatish Balay */
359e5c89e4eSSatish Balay 
360d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
361d71ae5a4SJacob Faibussowitsch {
362e5c89e4eSSatish Balay   int            err_ind, j;
363e5c89e4eSSatish Balay   fp_ctx_t       flt_context;
3643ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
365e5c89e4eSSatish Balay 
366e5c89e4eSSatish Balay   PetscFunctionBegin;
367e5c89e4eSSatish Balay   fp_sh_trap_info(scp, &flt_context);
368e5c89e4eSSatish Balay 
369e5c89e4eSSatish Balay   err_ind = -1;
370e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
371e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
372e5c89e4eSSatish Balay   }
373e5c89e4eSSatish Balay 
3743ba16761SJacob Faibussowitsch   if (err_ind >= 0) ierr = (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
3753ba16761SJacob Faibussowitsch   else ierr = (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
376a297a907SKarl Rupp 
3773ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
3783ba16761SJacob Faibussowitsch   (void)ierr;
37941e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
380e5c89e4eSSatish Balay }
381e5c89e4eSSatish Balay 
382d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
383d71ae5a4SJacob Faibussowitsch {
384e5c89e4eSSatish Balay   PetscFunctionBegin;
385bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
386e5c89e4eSSatish Balay     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
387e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
388bd2b07b1SBarry Smith     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
389bd2b07b1SBarry Smith     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
390e5c89e4eSSatish Balay   } else {
391e5c89e4eSSatish Balay     signal(SIGFPE, SIG_DFL);
392cc9df77eSBarry Smith     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
393e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
394e5c89e4eSSatish Balay   }
395cf0818bdSBarry Smith   _trapmode = flag;
396bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
3973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
398e5c89e4eSSatish Balay }
399e5c89e4eSSatish Balay 
400d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
401d71ae5a4SJacob Faibussowitsch {
402cc9df77eSBarry Smith   PetscFunctionBegin;
4039566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
405cc9df77eSBarry Smith }
406cc9df77eSBarry Smith 
407cc9df77eSBarry Smith /* ------------------------------------------------------------*/
408cc9df77eSBarry Smith #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
409cc9df77eSBarry Smith   #include <float.h>
410d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
411d71ae5a4SJacob Faibussowitsch {
4123ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
4133ba16761SJacob Faibussowitsch 
414cc9df77eSBarry Smith   PetscFunctionBegin;
4153ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
4163ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
4173ba16761SJacob Faibussowitsch   (void)ierr;
418cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
419cc9df77eSBarry Smith }
420cc9df77eSBarry Smith 
421d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
422d71ae5a4SJacob Faibussowitsch {
423cc9df77eSBarry Smith   unsigned int cw;
424cc9df77eSBarry Smith 
425cc9df77eSBarry Smith   PetscFunctionBegin;
426bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
427bd2b07b1SBarry Smith     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
428bd2b07b1SBarry Smith     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
42908401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
430cc9df77eSBarry Smith   } else {
431cc9df77eSBarry Smith     cw = 0;
43208401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
433cc9df77eSBarry Smith   }
434cc9df77eSBarry Smith   (void)_controlfp(0, cw);
435cf0818bdSBarry Smith   _trapmode = flag;
436bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
4373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
438cc9df77eSBarry Smith }
439cc9df77eSBarry Smith 
440d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
441d71ae5a4SJacob Faibussowitsch {
442cc9df77eSBarry Smith   PetscFunctionBegin;
4439566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
445cc9df77eSBarry Smith }
446cc9df77eSBarry Smith 
447cc9df77eSBarry Smith /* ------------------------------------------------------------*/
4489a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
449b014e56cSJed Brown   /*
450b014e56cSJed Brown    C99 style floating point environment.
451b014e56cSJed Brown 
452b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
453b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
454b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
455b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
456b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
457b014e56cSJed Brown */
458b014e56cSJed Brown   #include <fenv.h>
459accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
4609371c9d4SSatish Balay typedef struct {
4619371c9d4SSatish Balay   int         code;
4629371c9d4SSatish Balay   const char *name;
4639371c9d4SSatish Balay } FPNode;
464b014e56cSJed Brown static const FPNode error_codes[] = {
465b014e56cSJed Brown   {FE_DIVBYZERO, "divide by zero"                                 },
466b014e56cSJed Brown   {FE_INEXACT,   "inexact floating point result"                  },
467b014e56cSJed Brown   {FE_INVALID,   "invalid floating point arguments (domain error)"},
468b014e56cSJed Brown   {FE_OVERFLOW,  "floating point overflow"                        },
469b014e56cSJed Brown   {FE_UNDERFLOW, "floating point underflow"                       },
470b014e56cSJed Brown   {0,            "unknown error"                                  }
471b014e56cSJed Brown };
472accbd18bSBarry Smith   #endif
47399e0435eSBarry Smith 
474d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
475d71ae5a4SJacob Faibussowitsch {
476accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
477b014e56cSJed Brown   const FPNode  *node;
478b014e56cSJed Brown   int            code;
479ace3abfcSBarry Smith   PetscBool      matched = PETSC_FALSE;
480accbd18bSBarry Smith   #endif
4813ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
482b014e56cSJed Brown 
483b014e56cSJed Brown   PetscFunctionBegin;
484b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
485b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
486b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
4877d125cddSJed Brown    * more detail.
488b014e56cSJed Brown    */
489accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
490b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
491b014e56cSJed Brown   for (node = &error_codes[0]; node->code; node++) {
492b014e56cSJed Brown     if (code & node->code) {
493b014e56cSJed Brown       matched = PETSC_TRUE;
4943ba16761SJacob Faibussowitsch       ierr    = (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
495b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
496b014e56cSJed Brown     }
497b014e56cSJed Brown   }
498b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
4993ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
5003ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
5013ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
5023ba16761SJacob Faibussowitsch     ierr = (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
5033ba16761SJacob Faibussowitsch     ierr = (*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);
504b014e56cSJed Brown   }
505accbd18bSBarry Smith   #else
5063ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
507accbd18bSBarry Smith   #endif
5087d125cddSJed Brown 
5093ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("Try option -start_in_debugger\n");
51027104ee2SJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
511dfb7d7afSStefano Zampini     #if !PetscDefined(HAVE_THREADSAFETY)
5123ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("likely location of problem given in stack below\n");
5133ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
5143ba16761SJacob Faibussowitsch   ierr = PetscStackView(PETSC_STDOUT);
515dfb7d7afSStefano Zampini     #endif
51627104ee2SJacob Faibussowitsch   #else
5173ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
5183ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
51927104ee2SJacob Faibussowitsch   #endif
5203ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
5213ba16761SJacob Faibussowitsch   (void)ierr;
52241e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
523b014e56cSJed Brown }
524b014e56cSJed Brown 
525d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
526d71ae5a4SJacob Faibussowitsch {
527b014e56cSJed Brown   PetscFunctionBegin;
528bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
529b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
530cc73adaaSBarry Smith     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
531accbd18bSBarry Smith   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
532cc9df77eSBarry Smith     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
533cf0818bdSBarry Smith     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
534bd2b07b1SBarry Smith     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
535cf0818bdSBarry Smith     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
536bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
537b014e56cSJed Brown   #elif defined PETSC_HAVE_XMMINTRIN_H
538cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
539bd2b07b1SBarry Smith     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
540cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
541cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
542bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
543b014e56cSJed Brown   #else
544b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
545bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
546b014e56cSJed Brown   #endif
54708401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
548b014e56cSJed Brown   } else {
549cc73adaaSBarry Smith     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
550cc9df77eSBarry Smith     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
55108401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
552b014e56cSJed Brown   }
553cf0818bdSBarry Smith   _trapmode = flag;
5543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
555b014e56cSJed Brown }
556b014e56cSJed Brown 
557d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
558d71ae5a4SJacob Faibussowitsch {
559cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
560cc9df77eSBarry Smith   unsigned int flags;
561cc9df77eSBarry Smith   #endif
562cc9df77eSBarry Smith 
563cc9df77eSBarry Smith   PetscFunctionBegin;
564cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV)
565cc9df77eSBarry Smith   flags = fegetexcept();
566cc9df77eSBarry Smith   if (flags & FE_DIVBYZERO) {
567cc9df77eSBarry Smith   #elif defined PETSC_HAVE_XMMINTRIN_H
568cc9df77eSBarry Smith   flags = _MM_GET_EXCEPTION_MASK();
569cc9df77eSBarry Smith   if (!(flags & _MM_MASK_DIV_ZERO)) {
570cc9df77eSBarry Smith   #else
5719566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
5723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
573cc9df77eSBarry Smith   #endif
574cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
575cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_ON;
5769566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
577cc9df77eSBarry Smith   } else {
578cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_OFF;
5799566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
580cc9df77eSBarry Smith   }
5813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
582cc9df77eSBarry Smith   #endif
583cc9df77eSBarry Smith }
584cc9df77eSBarry Smith 
585cc9df77eSBarry Smith /* ------------------------------------------------------------*/
586cc9df77eSBarry Smith #elif defined(PETSC_HAVE_IEEEFP_H)
587cc9df77eSBarry Smith   #include <ieeefp.h>
588d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
589d71ae5a4SJacob Faibussowitsch {
5903ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
5913ba16761SJacob Faibussowitsch 
592cc9df77eSBarry Smith   PetscFunctionBegin;
5933ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
5943ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
5953ba16761SJacob Faibussowitsch   (void)ierr;
596cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
597cc9df77eSBarry Smith }
598cc9df77eSBarry Smith 
599d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
600d71ae5a4SJacob Faibussowitsch {
601cc9df77eSBarry Smith   PetscFunctionBegin;
602cf0818bdSBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
60318da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
604cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
605cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
606cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
607cc9df77eSBarry Smith   #endif
608cc9df77eSBarry Smith     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
60908401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
610cc9df77eSBarry Smith   } else {
61118da0197SPierre Jolivet   #if defined(PETSC_HAVE_FPRESETSTICKY)
612cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
613cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
614cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
615cc9df77eSBarry Smith   #endif
616cc9df77eSBarry Smith     fpsetmask(0);
61708401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
618cc9df77eSBarry Smith   }
619cf0818bdSBarry Smith   _trapmode = flag;
620bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
6213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
622cc9df77eSBarry Smith }
623cc9df77eSBarry Smith 
624d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
625d71ae5a4SJacob Faibussowitsch {
626cc9df77eSBarry Smith   PetscFunctionBegin;
6279566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
629cc9df77eSBarry Smith }
630cc9df77eSBarry Smith 
631e5c89e4eSSatish Balay /* -------------------------Default -----------------------------------*/
632e5c89e4eSSatish Balay #else
63399e0435eSBarry Smith 
634d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
635d71ae5a4SJacob Faibussowitsch {
6363ba16761SJacob Faibussowitsch   PetscErrorCode ierr;
6373ba16761SJacob Faibussowitsch 
638e5c89e4eSSatish Balay   PetscFunctionBegin;
6393ba16761SJacob Faibussowitsch   ierr = (*PetscErrorPrintf)("*** floating point error occurred ***\n");
6403ba16761SJacob Faibussowitsch   ierr = PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
6413ba16761SJacob Faibussowitsch   (void)ierr;
64241e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
643e5c89e4eSSatish Balay }
64499e0435eSBarry Smith 
645d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
646d71ae5a4SJacob Faibussowitsch {
647e5c89e4eSSatish Balay   PetscFunctionBegin;
648bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
6493ba16761SJacob Faibussowitsch     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) PetscCall((*PetscErrorPrintf)("Can't set floatingpoint handler\n"));
6503ba16761SJacob Faibussowitsch   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) PetscCall((*PetscErrorPrintf)("Can't clear floatingpoint handler\n"));
651a297a907SKarl Rupp 
652cf0818bdSBarry Smith   _trapmode = flag;
653bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
6543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
655e5c89e4eSSatish Balay }
656cc9df77eSBarry Smith 
657d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
658d71ae5a4SJacob Faibussowitsch {
659cc9df77eSBarry Smith   PetscFunctionBegin;
6609566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
6613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
662cc9df77eSBarry Smith }
663e5c89e4eSSatish Balay #endif
664