xref: /petsc/src/sys/error/fp.c (revision accbd18bd454ccd9075081900ae464bfc6a7e7b0)
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)
581f006be4SPierre Jolivet   #pragma omp 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));
66670f3ff9SJed Brown   PetscFunctionReturn(0);
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)
851f006be4SPierre Jolivet   #pragma omp critical
861f006be4SPierre Jolivet #endif
871f006be4SPierre Jolivet   {
88670f3ff9SJed Brown     link       = _trapstack;
89670f3ff9SJed Brown     _trapstack = _trapstack->next;
901f006be4SPierre Jolivet   }
919566063dSJacob Faibussowitsch   PetscCall(PetscFree(link));
92670f3ff9SJed Brown   PetscFunctionReturn(0);
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;
120e5c89e4eSSatish Balay 
121e5c89e4eSSatish Balay   PetscFunctionBegin;
1225f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
123e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
124e5c89e4eSSatish Balay   }
125e5c89e4eSSatish Balay 
126a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
127a297a907SKarl Rupp   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
128a297a907SKarl Rupp 
12949c86fc7SBarry Smith   (void)PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
13041e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
131e5c89e4eSSatish Balay   PetscFunctionReturn(0);
132e5c89e4eSSatish Balay }
133e5c89e4eSSatish Balay 
134e30d2299SSatish Balay /*@
135cf0818bdSBarry Smith    PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a
136cf0818bdSBarry Smith    subset of exceptions may be trapable.
137e5c89e4eSSatish Balay 
138e5c89e4eSSatish Balay    Not Collective
139e5c89e4eSSatish Balay 
140e5c89e4eSSatish Balay    Input Parameters:
141cf0818bdSBarry Smith .  flag - values are
142cf0818bdSBarry Smith .vb
143cf0818bdSBarry Smith     PETSC_FP_TRAP_OFF   - do not trap any exceptions
144cf0818bdSBarry Smith     PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow
145cf0818bdSBarry Smith     PETSC_FP_TRAP_INDIV - integer divide by zero
146cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number
147cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTOVF - overflow
148cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems
149cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTDIV - floating point divide by zero
150cf0818bdSBarry Smith     PETSC_FP_TRAP_FLTINEX - inexact floating point result
151cf0818bdSBarry Smith .ve
152e5c89e4eSSatish Balay 
153e5c89e4eSSatish Balay    Options Database Keys:
154cf0818bdSBarry Smith .  -fp_trap <off,on> - turn on or off trapping of floating point exceptions
155e5c89e4eSSatish Balay 
156e5c89e4eSSatish Balay    Level: advanced
157e5c89e4eSSatish Balay 
158cf0818bdSBarry Smith    Notes:
159811af0c4SBarry Smith    Currently only `PETSC_FP_TRAP_OFF` and `PETSC_FP_TRAP_ON` are handled. All others are treated as `PETSC_FP_TRAP_ON`.
160cf0818bdSBarry Smith 
161cf0818bdSBarry Smith    The values are bit values and may be |ed together in the function call
162cf0818bdSBarry Smith 
163cf0818bdSBarry Smith    On systems that support it this routine causes floating point
164cf0818bdSBarry Smith    overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to
165e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
166e5c89e4eSSatish Balay 
167cc9df77eSBarry Smith    On many common systems, the floating
1687d125cddSJed Brown    point exception state is not preserved from the location where the trap
1697d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1707d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1717d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
172cc9df77eSBarry Smith    break on the line where the error occurred.  On systems that support C99
173cc9df77eSBarry Smith    floating point exception handling You can check which
1747d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1757d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1767d125cddSJed Brown 
177db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
178e5c89e4eSSatish Balay @*/
179d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
180d71ae5a4SJacob Faibussowitsch {
181e5c89e4eSSatish Balay   char *out;
182e5c89e4eSSatish Balay 
183e5c89e4eSSatish Balay   PetscFunctionBegin;
184e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
185e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
186bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
187e5c89e4eSSatish Balay     /*
188a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
189e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
190e5c89e4eSSatish Balay     */
191a297a907SKarl Rupp     if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
192a297a907SKarl Rupp   } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
193a297a907SKarl Rupp 
194670f3ff9SJed Brown   _trapmode = flag;
195bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n"));
196e5c89e4eSSatish Balay   PetscFunctionReturn(0);
197e5c89e4eSSatish Balay }
198e5c89e4eSSatish Balay 
199cc9df77eSBarry Smith /*@
200811af0c4SBarry Smith    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when `PetscInitialize()` is called
201cc9df77eSBarry Smith 
202cc9df77eSBarry Smith    Not Collective
203cc9df77eSBarry Smith 
204811af0c4SBarry Smith    Note:
205cc9df77eSBarry Smith       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.
206cc9df77eSBarry Smith 
207ee300463SSatish Balay    Level: advanced
208cc9df77eSBarry Smith 
209db781477SPatrick Sanan .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()`
210cc9df77eSBarry Smith @*/
211d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
212d71ae5a4SJacob Faibussowitsch {
213cc9df77eSBarry Smith   PetscFunctionBegin;
2149566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
215cc9df77eSBarry Smith   PetscFunctionReturn(0);
216cc9df77eSBarry Smith }
217cc9df77eSBarry Smith 
218e5c89e4eSSatish Balay /* -------------------------------------------------------------------------------------------*/
219e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
220e5c89e4eSSatish Balay   #include <sunmath.h>
221e5c89e4eSSatish Balay   #include <floatingpoint.h>
222e5c89e4eSSatish Balay   #include <siginfo.h>
223e5c89e4eSSatish Balay   #include <ucontext.h>
224e5c89e4eSSatish Balay 
2259371c9d4SSatish Balay static struct {
2269371c9d4SSatish Balay   int   code_no;
2279371c9d4SSatish Balay   char *name;
2289371c9d4SSatish Balay } error_codes[] = {
229e5c89e4eSSatish Balay   {FPE_FLTINV, "invalid floating point operand"},
230e5c89e4eSSatish Balay   {FPE_FLTRES, "inexact floating point result" },
231e5c89e4eSSatish Balay   {FPE_FLTDIV, "division-by-zero"              },
232e5c89e4eSSatish Balay   {FPE_FLTUND, "floating point underflow"      },
233e5c89e4eSSatish Balay   {FPE_FLTOVF, "floating point overflow"       },
234e5c89e4eSSatish Balay   {0,          "unknown error"                 }
235e5c89e4eSSatish Balay };
236e5c89e4eSSatish Balay   #define SIGPC(scp) (scp->si_addr)
237e5c89e4eSSatish Balay 
238d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap)
239d71ae5a4SJacob Faibussowitsch {
2405f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = scp->si_code;
241e5c89e4eSSatish Balay 
242e5c89e4eSSatish Balay   PetscFunctionBegin;
2435f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
244e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
245e5c89e4eSSatish Balay   }
246e5c89e4eSSatish Balay 
247a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp));
248a297a907SKarl Rupp   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp));
249a297a907SKarl Rupp 
25049c86fc7SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
25141e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
252e5c89e4eSSatish Balay }
253e5c89e4eSSatish Balay 
254d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
255d71ae5a4SJacob Faibussowitsch {
256e5c89e4eSSatish Balay   char *out;
257e5c89e4eSSatish Balay 
258e5c89e4eSSatish Balay   PetscFunctionBegin;
259e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
260e5c89e4eSSatish Balay   (void)ieee_flags("clear", "exception", "all", &out);
261e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
262a297a907SKarl Rupp     if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n");
263cc9df77eSBarry Smith   } else {
264cc9df77eSBarry Smith     if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
265cc9df77eSBarry Smith   }
266670f3ff9SJed Brown   _trapmode = flag;
267bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n");
268e5c89e4eSSatish Balay   PetscFunctionReturn(0);
269e5c89e4eSSatish Balay }
270e5c89e4eSSatish Balay 
271d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
272d71ae5a4SJacob Faibussowitsch {
273cc9df77eSBarry Smith   PetscFunctionBegin;
2749566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
275cc9df77eSBarry Smith   PetscFunctionReturn(0);
276cc9df77eSBarry Smith }
277cc9df77eSBarry Smith 
278cc9df77eSBarry Smith /* ------------------------------------------------------------------------------------------*/
279e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
280e5c89e4eSSatish Balay   #include <sigfpe.h>
2819371c9d4SSatish Balay static struct {
2829371c9d4SSatish Balay   int   code_no;
2839371c9d4SSatish Balay   char *name;
2849371c9d4SSatish Balay } error_codes[] = {
285e5c89e4eSSatish Balay   {_INVALID, "IEEE operand error"      },
286e5c89e4eSSatish Balay   {_OVERFL,  "floating point overflow" },
287e5c89e4eSSatish Balay   {_UNDERFL, "floating point underflow"},
288e5c89e4eSSatish Balay   {_DIVZERO, "floating point divide"   },
289e5c89e4eSSatish Balay   {0,        "unknown error"           }
290e5c89e4eSSatish Balay };
291d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(unsigned exception[], int val[])
292d71ae5a4SJacob Faibussowitsch {
2935f80ce2aSJacob Faibussowitsch   int err_ind = -1, code = exception[0];
294e5c89e4eSSatish Balay 
295e5c89e4eSSatish Balay   PetscFunctionBegin;
2965f80ce2aSJacob Faibussowitsch   for (int j = 0; error_codes[j].code_no; j++) {
297e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
298e5c89e4eSSatish Balay   }
299a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
300a297a907SKarl Rupp   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code);
301a297a907SKarl Rupp 
30249c86fc7SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
30341e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
304e5c89e4eSSatish Balay }
305e5c89e4eSSatish Balay 
306d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
307d71ae5a4SJacob Faibussowitsch {
308e5c89e4eSSatish Balay   PetscFunctionBegin;
309bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0);
310cc9df77eSBarry Smith   else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0);
311670f3ff9SJed Brown   _trapmode = flag;
312bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n"));
313cc9df77eSBarry Smith   PetscFunctionReturn(0);
314cc9df77eSBarry Smith }
315cc9df77eSBarry Smith 
316d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
317d71ae5a4SJacob Faibussowitsch {
318cc9df77eSBarry Smith   PetscFunctionBegin;
3199566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
320cc9df77eSBarry Smith   PetscFunctionReturn(0);
321cc9df77eSBarry Smith }
322cc9df77eSBarry Smith 
323cc9df77eSBarry Smith /*----------------------------------------------- --------------------------------------------*/
324cc9df77eSBarry Smith #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
325e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
326e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
327e5c89e4eSSatish Balay struct sigcontext;
328e5c89e4eSSatish Balay   #include <fpxcp.h>
329e5c89e4eSSatish Balay   #include <fptrap.h>
330e5c89e4eSSatish Balay   #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
331e5c89e4eSSatish Balay   #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
332e5c89e4eSSatish Balay   #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
333e5c89e4eSSatish Balay   #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
334e5c89e4eSSatish Balay   #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
335e5c89e4eSSatish Balay 
3369371c9d4SSatish Balay static struct {
3379371c9d4SSatish Balay   int   code_no;
3389371c9d4SSatish Balay   char *name;
3399371c9d4SSatish Balay } error_codes[] = {
340e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP, "IEEE operand error"           },
341e5c89e4eSSatish Balay   {FPE_FLTOVF_TRAP,   "floating point overflow"      },
342e5c89e4eSSatish Balay   {FPE_FLTUND_TRAP,   "floating point underflow"     },
343e5c89e4eSSatish Balay   {FPE_FLTDIV_TRAP,   "floating point divide"        },
344e5c89e4eSSatish Balay   {FPE_FLTINEX_TRAP,  "inexact floating point result"},
345bd2b07b1SBarry Smith   < {0,                 "unknown error"                }
346e5c89e4eSSatish Balay };
347e5c89e4eSSatish Balay   #define SIGPC(scp)        (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
348e5c89e4eSSatish Balay /*
349e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
350e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
351e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
352e5c89e4eSSatish Balay */
353e5c89e4eSSatish Balay 
354d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp)
355d71ae5a4SJacob Faibussowitsch {
356e5c89e4eSSatish Balay   int      err_ind, j;
357e5c89e4eSSatish Balay   fp_ctx_t flt_context;
358e5c89e4eSSatish Balay 
359e5c89e4eSSatish Balay   PetscFunctionBegin;
360e5c89e4eSSatish Balay   fp_sh_trap_info(scp, &flt_context);
361e5c89e4eSSatish Balay 
362e5c89e4eSSatish Balay   err_ind = -1;
363e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
364e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
365e5c89e4eSSatish Balay   }
366e5c89e4eSSatish Balay 
367a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name);
368a297a907SKarl Rupp   else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap);
369a297a907SKarl Rupp 
37049c86fc7SBarry Smith   (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
37141e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
372e5c89e4eSSatish Balay }
373e5c89e4eSSatish Balay 
374d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
375d71ae5a4SJacob Faibussowitsch {
376e5c89e4eSSatish Balay   PetscFunctionBegin;
377bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
378e5c89e4eSSatish Balay     signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap);
379e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
380bd2b07b1SBarry Smith     /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */
381bd2b07b1SBarry Smith     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
382e5c89e4eSSatish Balay   } else {
383e5c89e4eSSatish Balay     signal(SIGFPE, SIG_DFL);
384cc9df77eSBarry Smith     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
385e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
386e5c89e4eSSatish Balay   }
387cf0818bdSBarry Smith   _trapmode = flag;
388bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n"));
389e5c89e4eSSatish Balay   PetscFunctionReturn(0);
390e5c89e4eSSatish Balay }
391e5c89e4eSSatish Balay 
392d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
393d71ae5a4SJacob Faibussowitsch {
394cc9df77eSBarry Smith   PetscFunctionBegin;
3959566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
396cc9df77eSBarry Smith   PetscFunctionReturn(0);
397cc9df77eSBarry Smith }
398cc9df77eSBarry Smith 
399cc9df77eSBarry Smith /* ------------------------------------------------------------*/
400cc9df77eSBarry Smith #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
401cc9df77eSBarry Smith   #include <float.h>
402d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
403d71ae5a4SJacob Faibussowitsch {
404cc9df77eSBarry Smith   PetscFunctionBegin;
405cc9df77eSBarry Smith   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
40649c86fc7SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
407cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
408cc9df77eSBarry Smith }
409cc9df77eSBarry Smith 
410d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
411d71ae5a4SJacob Faibussowitsch {
412cc9df77eSBarry Smith   unsigned int cw;
413cc9df77eSBarry Smith 
414cc9df77eSBarry Smith   PetscFunctionBegin;
415bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
416bd2b07b1SBarry Smith     /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */
417bd2b07b1SBarry Smith     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
41808401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
419cc9df77eSBarry Smith   } else {
420cc9df77eSBarry Smith     cw = 0;
42108401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
422cc9df77eSBarry Smith   }
423cc9df77eSBarry Smith   (void)_controlfp(0, cw);
424cf0818bdSBarry Smith   _trapmode = flag;
425bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n"));
426cc9df77eSBarry Smith   PetscFunctionReturn(0);
427cc9df77eSBarry Smith }
428cc9df77eSBarry Smith 
429d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
430d71ae5a4SJacob Faibussowitsch {
431cc9df77eSBarry Smith   PetscFunctionBegin;
4329566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
433cc9df77eSBarry Smith   PetscFunctionReturn(0);
434cc9df77eSBarry Smith }
435cc9df77eSBarry Smith 
436cc9df77eSBarry Smith /* ------------------------------------------------------------*/
4379a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
438b014e56cSJed Brown   /*
439b014e56cSJed Brown    C99 style floating point environment.
440b014e56cSJed Brown 
441b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
442b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
443b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
444b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
445b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
446b014e56cSJed Brown */
447b014e56cSJed Brown   #include <fenv.h>
448*accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
4499371c9d4SSatish Balay typedef struct {
4509371c9d4SSatish Balay   int         code;
4519371c9d4SSatish Balay   const char *name;
4529371c9d4SSatish Balay } FPNode;
453b014e56cSJed Brown static const FPNode error_codes[] = {
454b014e56cSJed Brown   {FE_DIVBYZERO, "divide by zero"                                 },
455b014e56cSJed Brown   {FE_INEXACT,   "inexact floating point result"                  },
456b014e56cSJed Brown   {FE_INVALID,   "invalid floating point arguments (domain error)"},
457b014e56cSJed Brown   {FE_OVERFLOW,  "floating point overflow"                        },
458b014e56cSJed Brown   {FE_UNDERFLOW, "floating point underflow"                       },
459b014e56cSJed Brown   {0,            "unknown error"                                  }
460b014e56cSJed Brown };
461*accbd18bSBarry Smith   #endif
46299e0435eSBarry Smith 
463d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
464d71ae5a4SJacob Faibussowitsch {
465*accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
466b014e56cSJed Brown   const FPNode *node;
467b014e56cSJed Brown   int           code;
468ace3abfcSBarry Smith   PetscBool     matched = PETSC_FALSE;
469*accbd18bSBarry Smith   #endif
470b014e56cSJed Brown 
471b014e56cSJed Brown   PetscFunctionBegin;
472b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
473b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
474b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
4757d125cddSJed Brown    * more detail.
476b014e56cSJed Brown    */
477*accbd18bSBarry Smith   #if defined(PETSC_HAVE_FE_VALUES)
478b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
479b014e56cSJed Brown   for (node = &error_codes[0]; node->code; node++) {
480b014e56cSJed Brown     if (code & node->code) {
481b014e56cSJed Brown       matched = PETSC_TRUE;
482b014e56cSJed Brown       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name);
483b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
484b014e56cSJed Brown     }
485b014e56cSJed Brown   }
486b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
487b014e56cSJed Brown     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
4887d125cddSJed Brown     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
4897d125cddSJed Brown     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT);
4907d125cddSJed Brown     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
4917d125cddSJed Brown     (*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);
492b014e56cSJed Brown   }
493*accbd18bSBarry Smith   #else
494*accbd18bSBarry Smith   (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
495*accbd18bSBarry Smith   #endif
4967d125cddSJed Brown 
4977d125cddSJed Brown   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
49827104ee2SJacob Faibussowitsch   #if PetscDefined(USE_DEBUG)
4997d125cddSJed Brown   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
5007d125cddSJed Brown   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
501639ff905SBarry Smith   PetscStackView(PETSC_STDOUT);
50227104ee2SJacob Faibussowitsch   #else
5037d125cddSJed Brown   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
5047d125cddSJed Brown   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
50527104ee2SJacob Faibussowitsch   #endif
50649c86fc7SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error");
50741e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
508b014e56cSJed Brown }
509b014e56cSJed Brown 
510d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
511d71ae5a4SJacob Faibussowitsch {
512b014e56cSJed Brown   PetscFunctionBegin;
513bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
514b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
515cc73adaaSBarry Smith     PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags");
516*accbd18bSBarry Smith   #if defined(FE_NOMASK_ENV) && defined(PETSC_HAVE_FE_VALUES)
517cc9df77eSBarry Smith     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
518cf0818bdSBarry Smith     /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */
519bd2b07b1SBarry Smith     /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */
520cf0818bdSBarry Smith     PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions");
521bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n"));
522b014e56cSJed Brown   #elif defined PETSC_HAVE_XMMINTRIN_H
523cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
524bd2b07b1SBarry Smith     /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */
525cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
526cc9df77eSBarry Smith     _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
527bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n"));
528b014e56cSJed Brown   #else
529b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
530bd2b07b1SBarry Smith     PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n"));
531b014e56cSJed Brown   #endif
53208401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
533b014e56cSJed Brown   } else {
534cc73adaaSBarry Smith     PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions");
535cc9df77eSBarry Smith     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
53608401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
537b014e56cSJed Brown   }
538cf0818bdSBarry Smith   _trapmode = flag;
539b014e56cSJed Brown   PetscFunctionReturn(0);
540b014e56cSJed Brown }
541b014e56cSJed Brown 
542d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
543d71ae5a4SJacob Faibussowitsch {
544cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
545cc9df77eSBarry Smith   unsigned int flags;
546cc9df77eSBarry Smith   #endif
547cc9df77eSBarry Smith 
548cc9df77eSBarry Smith   PetscFunctionBegin;
549cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV)
550cc9df77eSBarry Smith   flags = fegetexcept();
551cc9df77eSBarry Smith   if (flags & FE_DIVBYZERO) {
552cc9df77eSBarry Smith   #elif defined PETSC_HAVE_XMMINTRIN_H
553cc9df77eSBarry Smith   flags = _MM_GET_EXCEPTION_MASK();
554cc9df77eSBarry Smith   if (!(flags & _MM_MASK_DIV_ZERO)) {
555cc9df77eSBarry Smith   #else
5569566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n"));
557cc9df77eSBarry Smith   PetscFunctionReturn(0);
558cc9df77eSBarry Smith   #endif
559cc9df77eSBarry Smith   #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
560cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_ON;
5619566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags));
562cc9df77eSBarry Smith   } else {
563cc9df77eSBarry Smith     _trapmode = PETSC_FP_TRAP_OFF;
5649566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags));
565cc9df77eSBarry Smith   }
566cc9df77eSBarry Smith   PetscFunctionReturn(0);
567cc9df77eSBarry Smith   #endif
568cc9df77eSBarry Smith }
569cc9df77eSBarry Smith 
570cc9df77eSBarry Smith /* ------------------------------------------------------------*/
571cc9df77eSBarry Smith #elif defined(PETSC_HAVE_IEEEFP_H)
572cc9df77eSBarry Smith   #include <ieeefp.h>
573d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
574d71ae5a4SJacob Faibussowitsch {
575cc9df77eSBarry Smith   PetscFunctionBegin;
576cc9df77eSBarry Smith   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
57749c86fc7SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
578cc9df77eSBarry Smith   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
579cc9df77eSBarry Smith }
580cc9df77eSBarry Smith 
581d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
582d71ae5a4SJacob Faibussowitsch {
583cc9df77eSBarry Smith   PetscFunctionBegin;
584cf0818bdSBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
585cc9df77eSBarry Smith   #if defined(PETSC_HAVE_FPPRESETSTICKY)
586cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
587cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
588cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
589cc9df77eSBarry Smith   #endif
590cc9df77eSBarry Smith     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL);
59108401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler");
592cc9df77eSBarry Smith   } else {
593cc9df77eSBarry Smith   #if defined(PETSC_HAVE_FPPRESETSTICKY)
594cc9df77eSBarry Smith     fpresetsticky(fpgetsticky());
595cc9df77eSBarry Smith   #elif defined(PETSC_HAVE_FPSETSTICKY)
596cc9df77eSBarry Smith     fpsetsticky(fpgetsticky());
597cc9df77eSBarry Smith   #endif
598cc9df77eSBarry Smith     fpsetmask(0);
59908401ef6SPierre Jolivet     PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler");
600cc9df77eSBarry Smith   }
601cf0818bdSBarry Smith   _trapmode = flag;
602bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n"));
603cc9df77eSBarry Smith   PetscFunctionReturn(0);
604cc9df77eSBarry Smith }
605cc9df77eSBarry Smith 
606d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
607d71ae5a4SJacob Faibussowitsch {
608cc9df77eSBarry Smith   PetscFunctionBegin;
6099566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
610cc9df77eSBarry Smith   PetscFunctionReturn(0);
611cc9df77eSBarry Smith }
612cc9df77eSBarry Smith 
613e5c89e4eSSatish Balay /* -------------------------Default -----------------------------------*/
614e5c89e4eSSatish Balay #else
61599e0435eSBarry Smith 
616d71ae5a4SJacob Faibussowitsch void PetscDefaultFPTrap(int sig)
617d71ae5a4SJacob Faibussowitsch {
618e5c89e4eSSatish Balay   PetscFunctionBegin;
619e5c89e4eSSatish Balay   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
62049c86fc7SBarry Smith   PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error");
62141e02c4dSJunchao Zhang   PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP);
622e5c89e4eSSatish Balay }
62399e0435eSBarry Smith 
624d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
625d71ae5a4SJacob Faibussowitsch {
626e5c89e4eSSatish Balay   PetscFunctionBegin;
627bd2b07b1SBarry Smith   if (flag == PETSC_FP_TRAP_ON) {
628a297a907SKarl Rupp     if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
629a297a907SKarl Rupp   } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
630a297a907SKarl Rupp 
631cf0818bdSBarry Smith   _trapmode = flag;
632bd2b07b1SBarry Smith   PetscCall(PetscInfo(NULL, "Using default FPTRAP\n"));
633e5c89e4eSSatish Balay   PetscFunctionReturn(0);
634e5c89e4eSSatish Balay }
635cc9df77eSBarry Smith 
636d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDetermineInitialFPTrap(void)
637d71ae5a4SJacob Faibussowitsch {
638cc9df77eSBarry Smith   PetscFunctionBegin;
6399566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n"));
640cc9df77eSBarry Smith   PetscFunctionReturn(0);
641cc9df77eSBarry Smith }
642e5c89e4eSSatish Balay #endif
643