xref: /petsc/src/sys/error/fp.c (revision dbf62e16cdc1d232b534ec244cc0f4d44d5069e2)
17d0a6c19SBarry Smith 
2e5c89e4eSSatish Balay /*
3e5c89e4eSSatish Balay *   IEEE error handler for all machines. Since each machine has
4e5c89e4eSSatish Balay *   enough slight differences we have completely separate codes for each one.
5e5c89e4eSSatish Balay *
6e5c89e4eSSatish Balay */
7b014e56cSJed Brown 
8b014e56cSJed Brown /*
9b014e56cSJed Brown   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
10b014e56cSJed Brown   at the top of the file because other headers may pull in fenv.h even when
11b014e56cSJed Brown   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
12b014e56cSJed Brown   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
13b014e56cSJed Brown   shenanigans ought to be unnecessary.
14b014e56cSJed Brown */
15519f805aSKarl Rupp #if !defined(_GNU_SOURCE)
16b014e56cSJed Brown #define _GNU_SOURCE
1776a6984eSJed Brown #endif
18b014e56cSJed Brown 
19c6db04a5SJed Brown #include <petscsys.h>           /*I  "petscsys.h"  I*/
20e5c89e4eSSatish Balay #include <signal.h>
21e5c89e4eSSatish Balay #if defined(PETSC_HAVE_STDLIB_H)
22e5c89e4eSSatish Balay #include <stdlib.h>
23e5c89e4eSSatish Balay #endif
24e5c89e4eSSatish Balay 
25670f3ff9SJed Brown struct PetscFPTrapLink {
26670f3ff9SJed Brown   PetscFPTrap            trapmode;
27670f3ff9SJed Brown   struct PetscFPTrapLink *next;
28670f3ff9SJed Brown };
29670f3ff9SJed Brown static PetscFPTrap            _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode */
30670f3ff9SJed Brown static struct PetscFPTrapLink *_trapstack;                   /* Any pushed states of _trapmode */
31670f3ff9SJed Brown 
32670f3ff9SJed Brown #undef __FUNCT__
33670f3ff9SJed Brown #define __FUNCT__ "PetscFPTrapPush"
34670f3ff9SJed Brown /*@
35670f3ff9SJed Brown    PetscFPTrapPush - push a floating point trapping mode, to be restored using PetscFPTrapPop()
36670f3ff9SJed Brown 
37670f3ff9SJed Brown    Not Collective
38670f3ff9SJed Brown 
39670f3ff9SJed Brown    Input Arguments:
40670f3ff9SJed Brown . trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF
41670f3ff9SJed Brown 
42670f3ff9SJed Brown    Level: advanced
43670f3ff9SJed Brown 
44670f3ff9SJed Brown .seealso: PetscFPTrapPop(), PetscSetFPTrap()
45670f3ff9SJed Brown @*/
46670f3ff9SJed Brown PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
47670f3ff9SJed Brown {
48670f3ff9SJed Brown   PetscErrorCode         ierr;
49670f3ff9SJed Brown   struct PetscFPTrapLink *link;
50670f3ff9SJed Brown 
51670f3ff9SJed Brown   PetscFunctionBegin;
528caf3d72SBarry Smith   ierr           = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr);
53670f3ff9SJed Brown   link->trapmode = _trapmode;
54670f3ff9SJed Brown   link->next     = _trapstack;
55670f3ff9SJed Brown   _trapstack     = link;
56f6883b22SJed Brown   if (trap != _trapmode) {ierr = PetscSetFPTrap(trap);CHKERRQ(ierr);}
57670f3ff9SJed Brown   PetscFunctionReturn(0);
58670f3ff9SJed Brown }
59670f3ff9SJed Brown 
60670f3ff9SJed Brown #undef __FUNCT__
61670f3ff9SJed Brown #define __FUNCT__ "PetscFPTrapPop"
62670f3ff9SJed Brown /*@
63670f3ff9SJed Brown    PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop()
64670f3ff9SJed Brown 
65670f3ff9SJed Brown    Not Collective
66670f3ff9SJed Brown 
67670f3ff9SJed Brown    Level: advanced
68670f3ff9SJed Brown 
69670f3ff9SJed Brown .seealso: PetscFPTrapPush(), PetscSetFPTrap()
70670f3ff9SJed Brown @*/
71670f3ff9SJed Brown PetscErrorCode PetscFPTrapPop(void)
72670f3ff9SJed Brown {
73670f3ff9SJed Brown   PetscErrorCode         ierr;
74670f3ff9SJed Brown   struct PetscFPTrapLink *link;
75670f3ff9SJed Brown 
76670f3ff9SJed Brown   PetscFunctionBegin;
77f6883b22SJed Brown   if (_trapstack->trapmode != _trapmode) {ierr = PetscSetFPTrap(_trapstack->trapmode);CHKERRQ(ierr);}
78670f3ff9SJed Brown   link       = _trapstack;
79670f3ff9SJed Brown   _trapstack = _trapstack->next;
80670f3ff9SJed Brown   ierr       = PetscFree(link);CHKERRQ(ierr);
81670f3ff9SJed Brown   PetscFunctionReturn(0);
82670f3ff9SJed Brown }
83670f3ff9SJed Brown 
84e5c89e4eSSatish Balay /*--------------------------------------- ---------------------------------------------------*/
85e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
86e5c89e4eSSatish Balay #include <floatingpoint.h>
87e5c89e4eSSatish Balay 
88e5c89e4eSSatish Balay EXTERN_C_BEGIN
89e5c89e4eSSatish Balay PetscErrorCode ieee_flags(char*,char*,char*,char**);
90e5c89e4eSSatish Balay PetscErrorCode ieee_handler(char*,char*,sigfpe_handler_type(int,int,struct sigcontext*,char*));
91e5c89e4eSSatish Balay EXTERN_C_END
92e5c89e4eSSatish Balay 
93db32a245SJed Brown static struct { int code_no; char *name; } error_codes[] = {
94e5c89e4eSSatish Balay   { FPE_INTDIV_TRAP    ,"integer divide" },
95e5c89e4eSSatish Balay   { FPE_FLTOPERR_TRAP  ,"IEEE operand error" },
96e5c89e4eSSatish Balay   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
97e5c89e4eSSatish Balay   { FPE_FLTUND_TRAP    ,"floating point underflow" },
98e5c89e4eSSatish Balay   { FPE_FLTDIV_TRAP    ,"floating pointing divide" },
99e5c89e4eSSatish Balay   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
100e5c89e4eSSatish Balay   { 0                  ,"unknown error" }
101e5c89e4eSSatish Balay };
102e5c89e4eSSatish Balay #define SIGPC(scp) (scp->sc_pc)
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay #undef __FUNCT__
105e5c89e4eSSatish Balay #define __FUNCT__ "PetscDefaultFPTrap"
106e5c89e4eSSatish Balay sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
107e5c89e4eSSatish Balay {
108e5c89e4eSSatish Balay   PetscErrorCode ierr;
109e5c89e4eSSatish Balay   int            err_ind = -1,j;
110e5c89e4eSSatish Balay 
111e5c89e4eSSatish Balay   PetscFunctionBegin;
112e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
113e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
114e5c89e4eSSatish Balay   }
115e5c89e4eSSatish Balay 
116a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
117a297a907SKarl Rupp   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
118a297a907SKarl Rupp 
1195981cbfdSJed Brown   ierr = PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
120e5c89e4eSSatish Balay   MPI_Abort(PETSC_COMM_WORLD,0);
121e5c89e4eSSatish Balay   PetscFunctionReturn(0);
122e5c89e4eSSatish Balay }
123e5c89e4eSSatish Balay 
124e5c89e4eSSatish Balay #undef __FUNCT__
125e5c89e4eSSatish Balay #define __FUNCT__ "PetscSetFPTrap"
126e30d2299SSatish Balay /*@
127e5c89e4eSSatish Balay    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
128e5c89e4eSSatish Balay                     This option may not work on certain machines.
129e5c89e4eSSatish Balay 
130e5c89e4eSSatish Balay    Not Collective
131e5c89e4eSSatish Balay 
132e5c89e4eSSatish Balay    Input Parameters:
133e5c89e4eSSatish Balay .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.
134e5c89e4eSSatish Balay 
135e5c89e4eSSatish Balay    Options Database Keys:
136e5c89e4eSSatish Balay .  -fp_trap - Activates floating point trapping
137e5c89e4eSSatish Balay 
138e5c89e4eSSatish Balay    Level: advanced
139e5c89e4eSSatish Balay 
140e5c89e4eSSatish Balay    Description:
141e5c89e4eSSatish Balay    On systems that support it, this routine causes floating point
142e5c89e4eSSatish Balay    overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to
143e5c89e4eSSatish Balay    cause a message to be printed and the program to exit.
144e5c89e4eSSatish Balay 
1457d125cddSJed Brown    Note:
1467d125cddSJed Brown    On many common systems including x86 and x86-64 Linux, the floating
1477d125cddSJed Brown    point exception state is not preserved from the location where the trap
1487d125cddSJed Brown    occurred through to the signal handler.  In this case, the signal handler
1497d125cddSJed Brown    will just say that an unknown floating point exception occurred and which
1507d125cddSJed Brown    function it occurred in.  If you run with -fp_trap in a debugger, it will
1517d125cddSJed Brown    break on the line where the error occurred.  You can check which
1527d125cddSJed Brown    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
1537d125cddSJed Brown    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
1547d125cddSJed Brown 
155e5c89e4eSSatish Balay    Caution:
156e5c89e4eSSatish Balay    On certain machines, in particular the IBM rs6000, floating point
157e5c89e4eSSatish Balay    trapping is VERY slow!
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay    Concepts: floating point exceptions^trapping
160e5c89e4eSSatish Balay    Concepts: divide by zero
161e5c89e4eSSatish Balay 
162670f3ff9SJed Brown .seealso: PetscFPTrapPush(), PetscFPTrapPop()
163e5c89e4eSSatish Balay @*/
164e5c89e4eSSatish Balay PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
165e5c89e4eSSatish Balay {
166e5c89e4eSSatish Balay   char *out;
167e5c89e4eSSatish Balay 
168e5c89e4eSSatish Balay   PetscFunctionBegin;
169e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
170e5c89e4eSSatish Balay   (void) ieee_flags("clear","exception","all",&out);
171e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
172e5c89e4eSSatish Balay     /*
173a297a907SKarl Rupp       To trap more fp exceptions, including underflow, change the line below to
174e5c89e4eSSatish Balay       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
175e5c89e4eSSatish Balay     */
176a297a907SKarl Rupp     if (ieee_handler("set","common",PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
177a297a907SKarl Rupp   } else if (ieee_handler("clear","common",PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
178a297a907SKarl Rupp 
179670f3ff9SJed Brown   _trapmode = flag;
180e5c89e4eSSatish Balay   PetscFunctionReturn(0);
181e5c89e4eSSatish Balay }
182e5c89e4eSSatish Balay 
183e5c89e4eSSatish Balay /* -------------------------------------------------------------------------------------------*/
184e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
185e5c89e4eSSatish Balay #include <sunmath.h>
186e5c89e4eSSatish Balay #include <floatingpoint.h>
187e5c89e4eSSatish Balay #include <siginfo.h>
188e5c89e4eSSatish Balay #include <ucontext.h>
189e5c89e4eSSatish Balay 
190db32a245SJed Brown static struct { int code_no; char *name; } error_codes[] = {
191e5c89e4eSSatish Balay   { FPE_FLTINV,"invalid floating point operand"},
192e5c89e4eSSatish Balay   { FPE_FLTRES,"inexact floating point result"},
193e5c89e4eSSatish Balay   { FPE_FLTDIV,"division-by-zero"},
194e5c89e4eSSatish Balay   { FPE_FLTUND,"floating point underflow"},
195e5c89e4eSSatish Balay   { FPE_FLTOVF,"floating point overflow"},
196e5c89e4eSSatish Balay   { 0,         "unknown error"}
197e5c89e4eSSatish Balay };
198e5c89e4eSSatish Balay #define SIGPC(scp) (scp->si_addr)
199e5c89e4eSSatish Balay 
200e5c89e4eSSatish Balay #undef __FUNCT__
201e5c89e4eSSatish Balay #define __FUNCT__ "PetscDefaultFPTrap"
202e5c89e4eSSatish Balay void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
203e5c89e4eSSatish Balay {
204e5c89e4eSSatish Balay   int            err_ind,j,code = scp->si_code;
205e5c89e4eSSatish Balay   PetscErrorCode ierr;
206e5c89e4eSSatish Balay 
207e5c89e4eSSatish Balay   PetscFunctionBegin;
208e5c89e4eSSatish Balay   err_ind = -1;
209e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
210e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
211e5c89e4eSSatish Balay   }
212e5c89e4eSSatish Balay 
213a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
214a297a907SKarl Rupp   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
215a297a907SKarl Rupp 
2165981cbfdSJed Brown   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
217e5c89e4eSSatish Balay   MPI_Abort(PETSC_COMM_WORLD,0);
218e5c89e4eSSatish Balay }
219e5c89e4eSSatish Balay 
220e5c89e4eSSatish Balay #undef __FUNCT__
221e5c89e4eSSatish Balay #define __FUNCT__ "PetscSetFPTrap"
222e5c89e4eSSatish Balay PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
223e5c89e4eSSatish Balay {
224e5c89e4eSSatish Balay   char *out;
225e5c89e4eSSatish Balay 
226e5c89e4eSSatish Balay   PetscFunctionBegin;
227e5c89e4eSSatish Balay   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
228e5c89e4eSSatish Balay   (void) ieee_flags("clear","exception","all",&out);
229e5c89e4eSSatish Balay   if (flag == PETSC_FP_TRAP_ON) {
230a297a907SKarl Rupp     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
231a297a907SKarl Rupp   } else if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
232670f3ff9SJed Brown   _trapmode = flag;
233e5c89e4eSSatish Balay   PetscFunctionReturn(0);
234e5c89e4eSSatish Balay }
235e5c89e4eSSatish Balay 
236e5c89e4eSSatish Balay /* ------------------------------------------------------------------------------------------*/
237e5c89e4eSSatish Balay 
238e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
239e5c89e4eSSatish Balay #include <sigfpe.h>
240db32a245SJed Brown static struct { int code_no; char *name; } error_codes[] = {
241e5c89e4eSSatish Balay   { _INVALID   ,"IEEE operand error" },
242e5c89e4eSSatish Balay   { _OVERFL    ,"floating point overflow" },
243e5c89e4eSSatish Balay   { _UNDERFL   ,"floating point underflow" },
244e5c89e4eSSatish Balay   { _DIVZERO   ,"floating point divide" },
245e5c89e4eSSatish Balay   { 0          ,"unknown error" }
246e5c89e4eSSatish Balay } ;
247e5c89e4eSSatish Balay #undef __FUNCT__
248e5c89e4eSSatish Balay #define __FUNCT__ "PetscDefaultFPTrap"
249e5c89e4eSSatish Balay void PetscDefaultFPTrap(unsigned exception[],int val[])
250e5c89e4eSSatish Balay {
251e5c89e4eSSatish Balay   int err_ind,j,code;
252e5c89e4eSSatish Balay 
253e5c89e4eSSatish Balay   PetscFunctionBegin;
254e5c89e4eSSatish Balay   code    = exception[0];
255e5c89e4eSSatish Balay   err_ind = -1;
256e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
257e5c89e4eSSatish Balay     if (error_codes[j].code_no == code) err_ind = j;
258e5c89e4eSSatish Balay   }
259a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
260a297a907SKarl Rupp   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);
261a297a907SKarl Rupp 
2625981cbfdSJed Brown   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
263e5c89e4eSSatish Balay   MPI_Abort(PETSC_COMM_WORLD,0);
264e5c89e4eSSatish Balay }
265e5c89e4eSSatish Balay 
266e5c89e4eSSatish Balay #undef __FUNCT__
267e5c89e4eSSatish Balay #define __FUNCT__ "PetscSetFPTrap"
268e5c89e4eSSatish Balay PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
269e5c89e4eSSatish Balay {
270e5c89e4eSSatish Balay   PetscFunctionBegin;
271a297a907SKarl Rupp   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
272a297a907SKarl Rupp   else                          handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
273a297a907SKarl Rupp 
274670f3ff9SJed Brown   _trapmode = flag;
275e5c89e4eSSatish Balay   PetscFunctionReturn(0);
276e5c89e4eSSatish Balay }
277e5c89e4eSSatish Balay /*----------------------------------------------- --------------------------------------------*/
278e5c89e4eSSatish Balay /* In "fast" mode, floating point traps are imprecise and ignored.
279e5c89e4eSSatish Balay    This is the reason for the fptrap(FP_TRAP_SYNC) call */
280e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
281e5c89e4eSSatish Balay struct sigcontext;
282e5c89e4eSSatish Balay #include <fpxcp.h>
283e5c89e4eSSatish Balay #include <fptrap.h>
284e5c89e4eSSatish Balay #include <stdlib.h>
285e5c89e4eSSatish Balay #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
286e5c89e4eSSatish Balay #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
287e5c89e4eSSatish Balay #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
288e5c89e4eSSatish Balay #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
289e5c89e4eSSatish Balay #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
290e5c89e4eSSatish Balay 
291db32a245SJed Brown static struct { int code_no; char *name; } error_codes[] = {
292e5c89e4eSSatish Balay   {FPE_FLTOPERR_TRAP   ,"IEEE operand error" },
293e5c89e4eSSatish Balay   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
294e5c89e4eSSatish Balay   { FPE_FLTUND_TRAP    ,"floating point underflow" },
295e5c89e4eSSatish Balay   { FPE_FLTDIV_TRAP    ,"floating point divide" },
296e5c89e4eSSatish Balay   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
297e5c89e4eSSatish Balay   { 0                  ,"unknown error" }
298e5c89e4eSSatish Balay } ;
299e5c89e4eSSatish Balay #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
300e5c89e4eSSatish Balay /*
301e5c89e4eSSatish Balay    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
302e5c89e4eSSatish Balay    it looks like it should from the include definitions.  It is probably
303e5c89e4eSSatish Balay    some strange interaction with the "POSIX_SOURCE" that we require.
304e5c89e4eSSatish Balay */
305e5c89e4eSSatish Balay 
306e5c89e4eSSatish Balay #undef __FUNCT__
307e5c89e4eSSatish Balay #define __FUNCT__ "PetscDefaultFPTrap"
308e5c89e4eSSatish Balay void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
309e5c89e4eSSatish Balay {
310e5c89e4eSSatish Balay   PetscErrorCode ierr;
311e5c89e4eSSatish Balay   int            err_ind,j;
312e5c89e4eSSatish Balay   fp_ctx_t       flt_context;
313e5c89e4eSSatish Balay 
314e5c89e4eSSatish Balay   PetscFunctionBegin;
315e5c89e4eSSatish Balay   fp_sh_trap_info(scp,&flt_context);
316e5c89e4eSSatish Balay 
317e5c89e4eSSatish Balay   err_ind = -1;
318e5c89e4eSSatish Balay   for (j = 0; error_codes[j].code_no; j++) {
319e5c89e4eSSatish Balay     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
320e5c89e4eSSatish Balay   }
321e5c89e4eSSatish Balay 
322a297a907SKarl Rupp   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
323a297a907SKarl Rupp   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
324a297a907SKarl Rupp 
3255981cbfdSJed Brown   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
326e5c89e4eSSatish Balay   MPI_Abort(PETSC_COMM_WORLD,0);
327e5c89e4eSSatish Balay }
328e5c89e4eSSatish Balay 
329e5c89e4eSSatish Balay #undef __FUNCT__
330e5c89e4eSSatish Balay #define __FUNCT__ "PetscSetFPTrap"
331e5c89e4eSSatish Balay PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
332e5c89e4eSSatish Balay {
333e5c89e4eSSatish Balay   PetscFunctionBegin;
334e5c89e4eSSatish Balay   if (on == PETSC_FP_TRAP_ON) {
335e5c89e4eSSatish Balay     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
336e5c89e4eSSatish Balay     fp_trap(FP_TRAP_SYNC);
337e5c89e4eSSatish Balay     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
338e5c89e4eSSatish Balay     /* fp_enable(mask) for individual traps.  Values are:
339e5c89e4eSSatish Balay        TRP_INVALID
340e5c89e4eSSatish Balay        TRP_DIV_BY_ZERO
341e5c89e4eSSatish Balay        TRP_OVERFLOW
342e5c89e4eSSatish Balay        TRP_UNDERFLOW
343e5c89e4eSSatish Balay        TRP_INEXACT
344e5c89e4eSSatish Balay        Can OR then together.
345e5c89e4eSSatish Balay        fp_enable_all(); for all traps.
346e5c89e4eSSatish Balay     */
347e5c89e4eSSatish Balay   } else {
348e5c89e4eSSatish Balay     signal(SIGFPE,SIG_DFL);
349e5c89e4eSSatish Balay     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
350e5c89e4eSSatish Balay     fp_trap(FP_TRAP_OFF);
351e5c89e4eSSatish Balay   }
352670f3ff9SJed Brown   _trapmode = on;
353e5c89e4eSSatish Balay   PetscFunctionReturn(0);
354e5c89e4eSSatish Balay }
355e5c89e4eSSatish Balay 
3569a2402e9SBarry Smith #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
357b014e56cSJed Brown /*
358b014e56cSJed Brown    C99 style floating point environment.
359b014e56cSJed Brown 
360b014e56cSJed Brown    Note that C99 merely specifies how to save, restore, and clear the floating
361b014e56cSJed Brown    point environment as well as defining an enumeration of exception codes.  In
362b014e56cSJed Brown    particular, C99 does not specify how to make floating point exceptions raise
363b014e56cSJed Brown    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
364b014e56cSJed Brown    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
365b014e56cSJed Brown */
366b014e56cSJed Brown #include <fenv.h>
367b014e56cSJed Brown typedef struct {int code; const char *name;} FPNode;
368b014e56cSJed Brown static const FPNode error_codes[] = {
369b014e56cSJed Brown   {FE_DIVBYZERO,"divide by zero"},
370b014e56cSJed Brown   {FE_INEXACT,  "inexact floating point result"},
371b014e56cSJed Brown   {FE_INVALID,  "invalid floating point arguments (domain error)"},
372b014e56cSJed Brown   {FE_OVERFLOW, "floating point overflow"},
373b014e56cSJed Brown   {FE_UNDERFLOW,"floating point underflow"},
374b014e56cSJed Brown   {0           ,"unknown error"}
375b014e56cSJed Brown };
376b014e56cSJed Brown EXTERN_C_BEGIN
377b014e56cSJed Brown #undef __FUNCT__
378b014e56cSJed Brown #define __FUNCT__ "PetscDefaultFPTrap"
379b014e56cSJed Brown void PetscDefaultFPTrap(int sig)
380b014e56cSJed Brown {
381b014e56cSJed Brown   const FPNode *node;
382b014e56cSJed Brown   int          code;
383ace3abfcSBarry Smith   PetscBool    matched = PETSC_FALSE;
384b014e56cSJed Brown 
385b014e56cSJed Brown   PetscFunctionBegin;
386b014e56cSJed Brown   /* Note: While it is possible for the exception state to be preserved by the
387b014e56cSJed Brown    * kernel, this seems to be rare which makes the following flag testing almost
388b014e56cSJed Brown    * useless.  But on a system where the flags can be preserved, it would provide
3897d125cddSJed Brown    * more detail.
390b014e56cSJed Brown    */
391b014e56cSJed Brown   code = fetestexcept(FE_ALL_EXCEPT);
392b014e56cSJed Brown   for (node=&error_codes[0]; node->code; node++) {
393b014e56cSJed Brown     if (code & node->code) {
394b014e56cSJed Brown       matched = PETSC_TRUE;
395b014e56cSJed Brown       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
396b014e56cSJed Brown       code &= ~node->code; /* Unset this flag since it has been processed */
397b014e56cSJed Brown     }
398b014e56cSJed Brown   }
399b014e56cSJed Brown   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
400b014e56cSJed Brown     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
4017d125cddSJed Brown     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
4027d125cddSJed Brown     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
4037d125cddSJed Brown     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
4047d125cddSJed 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);
405b014e56cSJed Brown   }
4067d125cddSJed Brown 
4077d125cddSJed Brown   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
4088bf1f09cSShri Abhyankar #if defined(PETSC_USE_DEBUG)
409*dbf62e16SBarry Smith   if (!PetscStackActive()) (*PetscErrorPrintf)("  or try option -log_stack\n");
410a297a907SKarl Rupp   else {
4117d125cddSJed Brown     (*PetscErrorPrintf)("likely location of problem given in stack below\n");
4127d125cddSJed Brown     (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
413639ff905SBarry Smith     PetscStackView(PETSC_STDOUT);
4147d125cddSJed Brown   }
4157d125cddSJed Brown #endif
4167d125cddSJed Brown #if !defined(PETSC_USE_DEBUG)
4177d125cddSJed Brown   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
4187d125cddSJed Brown   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
4197d125cddSJed Brown #endif
420668f157eSBarry Smith   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
421b014e56cSJed Brown   MPI_Abort(PETSC_COMM_WORLD,0);
422b014e56cSJed Brown }
423b014e56cSJed Brown EXTERN_C_END
424b014e56cSJed Brown 
425b014e56cSJed Brown #undef __FUNCT__
426b014e56cSJed Brown #define __FUNCT__ "PetscSetFPTrap"
4277087cfbeSBarry Smith PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
428b014e56cSJed Brown {
429b014e56cSJed Brown   PetscFunctionBegin;
430b014e56cSJed Brown   if (on == PETSC_FP_TRAP_ON) {
431b014e56cSJed Brown     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
432e32f2f54SBarry Smith     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
433b014e56cSJed Brown #if defined FE_NOMASK_ENV
434b014e56cSJed Brown     /* We could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
435e32f2f54SBarry Smith     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
436b014e56cSJed Brown #elif defined PETSC_HAVE_XMMINTRIN_H
437b014e56cSJed Brown     _MM_SET_EXCEPTION_MASK(_MM_MASK_INEXACT);
438b014e56cSJed Brown #else
439b014e56cSJed Brown     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
440b014e56cSJed Brown #endif
441e32f2f54SBarry Smith     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
442b014e56cSJed Brown   } else {
443e32f2f54SBarry Smith     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
444e32f2f54SBarry Smith     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
445b014e56cSJed Brown   }
446670f3ff9SJed Brown   _trapmode = on;
447b014e56cSJed Brown   PetscFunctionReturn(0);
448b014e56cSJed Brown }
449b014e56cSJed Brown 
450e5c89e4eSSatish Balay /* -------------------------Default -----------------------------------*/
451e5c89e4eSSatish Balay #else
452e5c89e4eSSatish Balay EXTERN_C_BEGIN
453e5c89e4eSSatish Balay #undef __FUNCT__
454e5c89e4eSSatish Balay #define __FUNCT__ "PetscDefaultFPTrap"
455e5c89e4eSSatish Balay void PetscDefaultFPTrap(int sig)
456e5c89e4eSSatish Balay {
457e5c89e4eSSatish Balay   PetscFunctionBegin;
458e5c89e4eSSatish Balay   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
4590a78d522SHong Zhang   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
460e5c89e4eSSatish Balay   MPI_Abort(PETSC_COMM_WORLD,0);
461e5c89e4eSSatish Balay }
462e5c89e4eSSatish Balay EXTERN_C_END
463e5c89e4eSSatish Balay #undef __FUNCT__
464e5c89e4eSSatish Balay #define __FUNCT__ "PetscSetFPTrap"
4657087cfbeSBarry Smith PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
466e5c89e4eSSatish Balay {
467e5c89e4eSSatish Balay   PetscFunctionBegin;
468e5c89e4eSSatish Balay   if (on == PETSC_FP_TRAP_ON) {
469a297a907SKarl Rupp     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
470a297a907SKarl Rupp   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
471a297a907SKarl Rupp 
472670f3ff9SJed Brown   _trapmode = on;
473e5c89e4eSSatish Balay   PetscFunctionReturn(0);
474e5c89e4eSSatish Balay }
475e5c89e4eSSatish Balay #endif
476e5c89e4eSSatish Balay 
477e5c89e4eSSatish Balay 
478e5c89e4eSSatish Balay 
479