xref: /petsc/src/sys/error/fp.c (revision 2da392cc7c10228af19ad9843ce5155178acb644)
1 
2 /*
3 *   IEEE error handler for all machines. Since each OS has
4 *   enough slight differences we have completely separate codes for each one.
5 *
6 */
7 
8 /*
9   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
10   at the top of the file because other headers may pull in fenv.h even when
11   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
12   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
13   shenanigans ought to be unnecessary.
14 */
15 #if !defined(_GNU_SOURCE)
16 #define _GNU_SOURCE
17 #endif
18 
19 #include <petscsys.h>           /*I  "petscsys.h"  I*/
20 #include <signal.h>
21 
22 struct PetscFPTrapLink {
23   PetscFPTrap            trapmode;
24   struct PetscFPTrapLink *next;
25 };
26 static PetscFPTrap            _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */
27 static struct PetscFPTrapLink *_trapstack;                   /* Any pushed states of _trapmode */
28 
29 /*@
30    PetscFPTrapPush - push a floating point trapping mode, restored using PetscFPTrapPop()
31 
32    Not Collective
33 
34    Input Arguments:
35 .    trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF
36 
37    Level: advanced
38 
39    Notes:
40      This only changes the trapping if the new mode is different than the current mode.
41 
42      This routine is called to turn off trapping for certain LAPACK routines that assume that dividing
43      by zero is acceptable. In particular the routine ieeeck().
44 
45      Most systems by default have all trapping turned off, but certain Fortran compilers have
46      link flags that turn on trapping before the program begins.
47 $       gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal
48 $       ifort -fpe0
49 
50 .seealso: PetscFPTrapPop(), PetscSetFPTrap(), PetscDetermineInitialFPTrap()
51 @*/
52 PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
53 {
54   PetscErrorCode         ierr;
55   struct PetscFPTrapLink *link;
56 
57   PetscFunctionBegin;
58   ierr           = PetscNew(&link);CHKERRQ(ierr);
59   link->trapmode = _trapmode;
60   link->next     = _trapstack;
61   _trapstack     = link;
62   if (trap != _trapmode) {ierr = PetscSetFPTrap(trap);CHKERRQ(ierr);}
63   PetscFunctionReturn(0);
64 }
65 
66 /*@
67    PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop()
68 
69    Not Collective
70 
71    Level: advanced
72 
73 .seealso: PetscFPTrapPush(), PetscSetFPTrap(), PetscDetermineInitialFPTrap()
74 @*/
75 PetscErrorCode PetscFPTrapPop(void)
76 {
77   PetscErrorCode         ierr;
78   struct PetscFPTrapLink *link;
79 
80   PetscFunctionBegin;
81   if (_trapstack->trapmode != _trapmode) {ierr = PetscSetFPTrap(_trapstack->trapmode);CHKERRQ(ierr);}
82   link       = _trapstack;
83   _trapstack = _trapstack->next;
84   ierr       = PetscFree(link);CHKERRQ(ierr);
85   PetscFunctionReturn(0);
86 }
87 
88 /*--------------------------------------- ---------------------------------------------------*/
89 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
90 #include <floatingpoint.h>
91 
92 PETSC_EXTERN PetscErrorCode ieee_flags(char*,char*,char*,char**);
93 PETSC_EXTERN PetscErrorCode ieee_handler(char*,char*,sigfpe_handler_type(int,int,struct sigcontext*,char*));
94 
95 static struct { int code_no; char *name; } error_codes[] = {
96   { FPE_INTDIV_TRAP    ,"integer divide" },
97   { FPE_FLTOPERR_TRAP  ,"IEEE operand error" },
98   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
99   { FPE_FLTUND_TRAP    ,"floating point underflow" },
100   { FPE_FLTDIV_TRAP    ,"floating pointing divide" },
101   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
102   { 0                  ,"unknown error" }
103 };
104 #define SIGPC(scp) (scp->sc_pc)
105 
106 sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
107 {
108   PetscErrorCode ierr;
109   int            err_ind = -1,j;
110 
111   PetscFunctionBegin;
112   for (j = 0; error_codes[j].code_no; j++) {
113     if (error_codes[j].code_no == code) err_ind = j;
114   }
115 
116   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
117   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
118 
119   ierr = PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
120   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
121   PetscFunctionReturn(0);
122 }
123 
124 /*@
125    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
126                     This option may not work on certain systems.
127 
128    Not Collective
129 
130    Input Parameters:
131 .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.
132 
133    Options Database Keys:
134 .  -fp_trap - Activates floating point trapping
135 
136    Level: advanced
137 
138    Description:
139    On systems that support it, when called with PETSC_FP_TRAP_ON this routine causes floating point
140    underflow, overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to
141    cause a message to be printed and the program to exit.
142 
143    Note:
144    On many common systems, the floating
145    point exception state is not preserved from the location where the trap
146    occurred through to the signal handler.  In this case, the signal handler
147    will just say that an unknown floating point exception occurred and which
148    function it occurred in.  If you run with -fp_trap in a debugger, it will
149    break on the line where the error occurred.  On systems that support C99
150    floating point exception handling You can check which
151    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
152    (usually at /usr/include/bits/fenv.h) for the enum values on your system.
153 
154    Caution:
155    On certain machines, in particular the IBM PowerPC, floating point
156    trapping may be VERY slow!
157 
158 
159 .seealso: PetscFPTrapPush(), PetscFPTrapPop(), PetscDetermineInitialFPTrap()
160 @*/
161 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
162 {
163   char *out;
164 
165   PetscFunctionBegin;
166   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
167   (void) ieee_flags("clear","exception","all",&out);
168   if (flag == PETSC_FP_TRAP_ON) {
169     /*
170       To trap more fp exceptions, including underflow, change the line below to
171       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
172     */
173     if (ieee_handler("set","common",PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
174   } else if (ieee_handler("clear","common",PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
175 
176   _trapmode = flag;
177   PetscFunctionReturn(0);
178 }
179 
180 /*@
181    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when PetscInitialize() is called
182 
183    Not Collective
184 
185    Notes:
186       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.
187 
188 
189 .seealso: PetscFPTrapPush(), PetscFPTrapPop(), PetscDetermineInitialFPTrap()
190 @*/
191 PetscErrorCode  PetscDetermineInitialFPTrap(void)
192 {
193   PetscErrorCode ierr;
194 
195   PetscFunctionBegin;
196   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
197   PetscFunctionReturn(0);
198 }
199 
200 /* -------------------------------------------------------------------------------------------*/
201 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
202 #include <sunmath.h>
203 #include <floatingpoint.h>
204 #include <siginfo.h>
205 #include <ucontext.h>
206 
207 static struct { int code_no; char *name; } error_codes[] = {
208   { FPE_FLTINV,"invalid floating point operand"},
209   { FPE_FLTRES,"inexact floating point result"},
210   { FPE_FLTDIV,"division-by-zero"},
211   { FPE_FLTUND,"floating point underflow"},
212   { FPE_FLTOVF,"floating point overflow"},
213   { 0,         "unknown error"}
214 };
215 #define SIGPC(scp) (scp->si_addr)
216 
217 void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
218 {
219   int            err_ind,j,code = scp->si_code;
220   PetscErrorCode ierr;
221 
222   PetscFunctionBegin;
223   err_ind = -1;
224   for (j = 0; error_codes[j].code_no; j++) {
225     if (error_codes[j].code_no == code) err_ind = j;
226   }
227 
228   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
229   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
230 
231   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
232   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
233 }
234 
235 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
236 {
237   char *out;
238 
239   PetscFunctionBegin;
240   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
241   (void) ieee_flags("clear","exception","all",&out);
242   if (flag == PETSC_FP_TRAP_ON) {
243     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
244   } else {
245     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
246   }
247   _trapmode = flag;
248   PetscFunctionReturn(0);
249 }
250 
251 PetscErrorCode  PetscDetermineInitialFPTrap(void)
252 {
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
257   PetscFunctionReturn(0);
258 }
259 
260 /* ------------------------------------------------------------------------------------------*/
261 #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
262 #include <sigfpe.h>
263 static struct { int code_no; char *name; } error_codes[] = {
264   { _INVALID   ,"IEEE operand error" },
265   { _OVERFL    ,"floating point overflow" },
266   { _UNDERFL   ,"floating point underflow" },
267   { _DIVZERO   ,"floating point divide" },
268   { 0          ,"unknown error" }
269 } ;
270 void PetscDefaultFPTrap(unsigned exception[],int val[])
271 {
272   int err_ind,j,code;
273 
274   PetscFunctionBegin;
275   code    = exception[0];
276   err_ind = -1;
277   for (j = 0; error_codes[j].code_no; j++) {
278     if (error_codes[j].code_no == code) err_ind = j;
279   }
280   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
281   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);
282 
283   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
284   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
285 }
286 
287 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
288 {
289   PetscFunctionBegin;
290   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON,,_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
291   else                          handle_sigfpes(_OFF,_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
292   _trapmode = flag;
293   PetscFunctionReturn(0);
294 }
295 
296 PetscErrorCode  PetscDetermineInitialFPTrap(void)
297 {
298   PetscErrorCode ierr;
299 
300   PetscFunctionBegin;
301   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
302   PetscFunctionReturn(0);
303 }
304 
305 /* -------------------------------------------------------------------------------------------*/
306 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
307 #include <sunmath.h>
308 #include <floatingpoint.h>
309 #include <siginfo.h>
310 #include <ucontext.h>
311 
312 static struct { int code_no; char *name; } error_codes[] = {
313   { FPE_FLTINV,"invalid floating point operand"},
314   { FPE_FLTRES,"inexact floating point result"},
315   { FPE_FLTDIV,"division-by-zero"},
316   { FPE_FLTUND,"floating point underflow"},
317   { FPE_FLTOVF,"floating point overflow"},
318   { 0,         "unknown error"}
319 };
320 #define SIGPC(scp) (scp->si_addr)
321 
322 void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
323 {
324   int            err_ind,j,code = scp->si_code;
325   PetscErrorCode ierr;
326 
327   PetscFunctionBegin;
328   err_ind = -1;
329   for (j = 0; error_codes[j].code_no; j++) {
330     if (error_codes[j].code_no == code) err_ind = j;
331   }
332 
333   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
334   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
335 
336   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
337   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
338 }
339 
340 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
341 {
342   char *out;
343 
344   PetscFunctionBegin;
345   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
346   (void) ieee_flags("clear","exception","all",&out);
347   if (flag == PETSC_FP_TRAP_ON) {
348     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
349   } else {
350     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
351   }
352   _trapmode = flag;
353   PetscFunctionReturn(0);
354 }
355 
356 PetscErrorCode  PetscDetermineInitialFPTrap(void)
357 {
358   PetscErrorCode ierr;
359 
360   PetscFunctionBegin;
361   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
362   PetscFunctionReturn(0);
363 }
364 
365 /*----------------------------------------------- --------------------------------------------*/
366 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
367 /* In "fast" mode, floating point traps are imprecise and ignored.
368    This is the reason for the fptrap(FP_TRAP_SYNC) call */
369 struct sigcontext;
370 #include <fpxcp.h>
371 #include <fptrap.h>
372 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
373 #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
374 #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
375 #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
376 #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
377 
378 static struct { int code_no; char *name; } error_codes[] = {
379   {FPE_FLTOPERR_TRAP   ,"IEEE operand error" },
380   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
381   { FPE_FLTUND_TRAP    ,"floating point underflow" },
382   { FPE_FLTDIV_TRAP    ,"floating point divide" },
383   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
384   { 0                  ,"unknown error" }
385 } ;
386 #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
387 /*
388    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
389    it looks like it should from the include definitions.  It is probably
390    some strange interaction with the "POSIX_SOURCE" that we require.
391 */
392 
393 void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
394 {
395   PetscErrorCode ierr;
396   int            err_ind,j;
397   fp_ctx_t       flt_context;
398 
399   PetscFunctionBegin;
400   fp_sh_trap_info(scp,&flt_context);
401 
402   err_ind = -1;
403   for (j = 0; error_codes[j].code_no; j++) {
404     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
405   }
406 
407   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
408   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
409 
410   ierr = PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
411   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
412 }
413 
414 PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
415 {
416   PetscFunctionBegin;
417   if (on == PETSC_FP_TRAP_ON) {
418     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
419     fp_trap(FP_TRAP_SYNC);
420     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
421     /* fp_enable(mask) for individual traps.  Values are:
422        TRP_INVALID
423        TRP_DIV_BY_ZERO
424        TRP_OVERFLOW
425        TRP_UNDERFLOW
426        TRP_INEXACT
427        Can OR then together.
428        fp_enable_all(); for all traps.
429     */
430   } else {
431     signal(SIGFPE,SIG_DFL);
432     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
433     fp_trap(FP_TRAP_OFF);
434   }
435   _trapmode = on;
436   PetscFunctionReturn(0);
437 }
438 
439 PetscErrorCode  PetscDetermineInitialFPTrap(void)
440 {
441   PetscErrorCode ierr;
442 
443   PetscFunctionBegin;
444   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
445   PetscFunctionReturn(0);
446 }
447 
448 /* ------------------------------------------------------------*/
449 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
450 #include <float.h>
451 void PetscDefaultFPTrap(int sig)
452 {
453   PetscFunctionBegin;
454   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
455   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
456   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
457 }
458 
459 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
460 {
461   unsigned int cw;
462 
463   PetscFunctionBegin;
464   if (on == PETSC_FP_TRAP_ON) {
465     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW;
466     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
467   } else {
468     cw = 0;
469     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
470   }
471   (void)_controlfp(0, cw);
472   _trapmode = on;
473   PetscFunctionReturn(0);
474 }
475 
476 PetscErrorCode  PetscDetermineInitialFPTrap(void)
477 {
478   PetscErrorCode ierr;
479 
480   PetscFunctionBegin;
481   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
482   PetscFunctionReturn(0);
483 }
484 
485 /* ------------------------------------------------------------*/
486 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
487 /*
488    C99 style floating point environment.
489 
490    Note that C99 merely specifies how to save, restore, and clear the floating
491    point environment as well as defining an enumeration of exception codes.  In
492    particular, C99 does not specify how to make floating point exceptions raise
493    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
494    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
495 */
496 #include <fenv.h>
497 typedef struct {int code; const char *name;} FPNode;
498 static const FPNode error_codes[] = {
499   {FE_DIVBYZERO,"divide by zero"},
500   {FE_INEXACT,  "inexact floating point result"},
501   {FE_INVALID,  "invalid floating point arguments (domain error)"},
502   {FE_OVERFLOW, "floating point overflow"},
503   {FE_UNDERFLOW,"floating point underflow"},
504   {0           ,"unknown error"}
505 };
506 
507 void PetscDefaultFPTrap(int sig)
508 {
509   const FPNode *node;
510   int          code;
511   PetscBool    matched = PETSC_FALSE;
512 
513   PetscFunctionBegin;
514   /* Note: While it is possible for the exception state to be preserved by the
515    * kernel, this seems to be rare which makes the following flag testing almost
516    * useless.  But on a system where the flags can be preserved, it would provide
517    * more detail.
518    */
519   code = fetestexcept(FE_ALL_EXCEPT);
520   for (node=&error_codes[0]; node->code; node++) {
521     if (code & node->code) {
522       matched = PETSC_TRUE;
523       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
524       code &= ~node->code; /* Unset this flag since it has been processed */
525     }
526   }
527   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
528     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
529     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
530     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
531     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
532     (*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);
533   }
534 
535   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
536   if (PetscDefined(USE_DEBUG)) {
537     if (!PetscStackActive()) (*PetscErrorPrintf)("  or try option -log_stack\n");
538     else {
539       (*PetscErrorPrintf)("likely location of problem given in stack below\n");
540       (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
541       PetscStackView(PETSC_STDOUT);
542     }
543   } else {
544     (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
545     (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
546   }
547   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
548   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
549 }
550 
551 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
552 {
553   PetscFunctionBegin;
554   if (on == PETSC_FP_TRAP_ON) {
555     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
556     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
557 #if defined(FE_NOMASK_ENV)
558     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
559     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
560 #elif defined PETSC_HAVE_XMMINTRIN_H
561    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
562    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
563    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
564    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
565 #else
566     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
567 #endif
568     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
569   } else {
570     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
571     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
572     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
573   }
574   _trapmode = on;
575   PetscFunctionReturn(0);
576 }
577 
578 PetscErrorCode  PetscDetermineInitialFPTrap(void)
579 {
580 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
581   unsigned int   flags;
582 #endif
583   PetscErrorCode ierr;
584 
585   PetscFunctionBegin;
586 #if defined(FE_NOMASK_ENV)
587   flags = fegetexcept();
588   if (flags & FE_DIVBYZERO) {
589 #elif defined PETSC_HAVE_XMMINTRIN_H
590   flags = _MM_GET_EXCEPTION_MASK();
591   if (!(flags & _MM_MASK_DIV_ZERO)) {
592 #else
593   ierr = PetscInfo(NULL,"Floating point trapping unknown, assuming off\n");CHKERRQ(ierr);
594   PetscFunctionReturn(0);
595 #endif
596 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
597     _trapmode = PETSC_FP_TRAP_ON;
598     ierr = PetscInfo1(NULL,"Floating point trapping is on by default %d\n",flags);CHKERRQ(ierr);
599   } else {
600     _trapmode = PETSC_FP_TRAP_OFF;
601     ierr = PetscInfo1(NULL,"Floating point trapping is off by default %d\n",flags);CHKERRQ(ierr);
602   }
603   PetscFunctionReturn(0);
604 #endif
605 }
606 
607 /* ------------------------------------------------------------*/
608 #elif defined(PETSC_HAVE_IEEEFP_H)
609 #include <ieeefp.h>
610 void PetscDefaultFPTrap(int sig)
611 {
612   PetscFunctionBegin;
613   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
614   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
615   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
616 }
617 
618 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
619 {
620   PetscFunctionBegin;
621   if (on == PETSC_FP_TRAP_ON) {
622 #if defined(PETSC_HAVE_FPPRESETSTICKY)
623     fpresetsticky(fpgetsticky());
624 #elif defined(PETSC_HAVE_FPSETSTICKY)
625     fpsetsticky(fpgetsticky());
626 #endif
627     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL |  FP_X_OFL);
628     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
629   } else {
630 #if defined(PETSC_HAVE_FPPRESETSTICKY)
631     fpresetsticky(fpgetsticky());
632 #elif defined(PETSC_HAVE_FPSETSTICKY)
633     fpsetsticky(fpgetsticky());
634 #endif
635     fpsetmask(0);
636     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
637   }
638   _trapmode = on;
639   PetscFunctionReturn(0);
640 }
641 
642 PetscErrorCode  PetscDetermineInitialFPTrap(void)
643 {
644   PetscErrorCode ierr;
645 
646   PetscFunctionBegin;
647   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
648   PetscFunctionReturn(0);
649 }
650 
651 /* -------------------------Default -----------------------------------*/
652 #else
653 
654 void PetscDefaultFPTrap(int sig)
655 {
656   PetscFunctionBegin;
657   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
658   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
659   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
660 }
661 
662 PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
663 {
664   PetscFunctionBegin;
665   if (on == PETSC_FP_TRAP_ON) {
666     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
667   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
668 
669   _trapmode = on;
670   PetscFunctionReturn(0);
671 }
672 
673 PetscErrorCode  PetscDetermineInitialFPTrap(void)
674 {
675   PetscErrorCode ierr;
676 
677   PetscFunctionBegin;
678   ierr = PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");CHKERRQ(ierr);
679   PetscFunctionReturn(0);
680 }
681 #endif
682 
683 
684 
685