Actual source code: fp.c


  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: */

  7: /*
  8:   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
  9:   at the top of the file because other headers may pull in fenv.h even when
 10:   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
 11:   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
 12:   shenanigans ought to be unnecessary.
 13: */
 14: #if !defined(_GNU_SOURCE)
 15: #define _GNU_SOURCE
 16: #endif

 18: #include <petsc/private/petscimpl.h>
 19: #include <signal.h>

 21: struct PetscFPTrapLink {
 22:   PetscFPTrap            trapmode;
 23:   struct PetscFPTrapLink *next;
 24: };
 25: static PetscFPTrap            _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */
 26: static struct PetscFPTrapLink *_trapstack;                   /* Any pushed states of _trapmode */

 28: /*@
 29:    PetscFPTrapPush - push a floating point trapping mode, restored using PetscFPTrapPop()

 31:    Not Collective

 33:    Input Parameter:
 34: .    trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF

 36:    Level: advanced

 38:    Notes:
 39:      This only changes the trapping if the new mode is different than the current mode.

 41:      This routine is called to turn off trapping for certain LAPACK routines that assume that dividing
 42:      by zero is acceptable. In particular the routine ieeeck().

 44:      Most systems by default have all trapping turned off, but certain Fortran compilers have
 45:      link flags that turn on trapping before the program begins.
 46: $       gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal
 47: $       ifort -fpe0

 49: .seealso: PetscFPTrapPop(), PetscSetFPTrap(), PetscDetermineInitialFPTrap()
 50: @*/
 51: PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
 52: {
 53:   struct PetscFPTrapLink *link;

 55:   PetscNew(&link);
 56:   link->trapmode = _trapmode;
 57:   link->next     = _trapstack;
 58:   _trapstack     = link;
 59:   if (trap != _trapmode) PetscSetFPTrap(trap);
 60:   return 0;
 61: }

 63: /*@
 64:    PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop()

 66:    Not Collective

 68:    Level: advanced

 70: .seealso: PetscFPTrapPush(), PetscSetFPTrap(), PetscDetermineInitialFPTrap()
 71: @*/
 72: PetscErrorCode PetscFPTrapPop(void)
 73: {
 74:   struct PetscFPTrapLink *link;

 76:   if (_trapstack->trapmode != _trapmode) PetscSetFPTrap(_trapstack->trapmode);
 77:   link       = _trapstack;
 78:   _trapstack = _trapstack->next;
 79:   PetscFree(link);
 80:   return 0;
 81: }

 83: /*--------------------------------------- ---------------------------------------------------*/
 84: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
 85: #include <floatingpoint.h>

 87: PETSC_EXTERN PetscErrorCode ieee_flags(char*,char*,char*,char**);
 88: PETSC_EXTERN PetscErrorCode ieee_handler(char*,char*,sigfpe_handler_type(int,int,struct sigcontext*,char*));

 90: static struct { int code_no; char *name; } error_codes[] = {
 91:   { FPE_INTDIV_TRAP    ,"integer divide" },
 92:   { FPE_FLTOPERR_TRAP  ,"IEEE operand error" },
 93:   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
 94:   { FPE_FLTUND_TRAP    ,"floating point underflow" },
 95:   { FPE_FLTDIV_TRAP    ,"floating pointing divide" },
 96:   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
 97:   { 0                  ,"unknown error" }
 98: };
 99: #define SIGPC(scp) (scp->sc_pc)

101: sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
102: {
103:   int err_ind = -1;

105:   for (int j = 0; error_codes[j].code_no; j++) {
106:     if (error_codes[j].code_no == code) err_ind = j;
107:   }

109:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
110:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));

112:   (void)PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
113:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
114:   return 0;
115: }

117: /*@
118:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
119:                     This option may not work on certain systems.

121:    Not Collective

123:    Input Parameters:
124: .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.

126:    Options Database Keys:
127: .  -fp_trap - Activates floating point trapping

129:    Level: advanced

131:    Description:
132:    On systems that support it, when called with PETSC_FP_TRAP_ON this routine causes floating point
133:    underflow, overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to
134:    cause a message to be printed and the program to exit.

136:    Note:
137:    On many common systems, the floating
138:    point exception state is not preserved from the location where the trap
139:    occurred through to the signal handler.  In this case, the signal handler
140:    will just say that an unknown floating point exception occurred and which
141:    function it occurred in.  If you run with -fp_trap in a debugger, it will
142:    break on the line where the error occurred.  On systems that support C99
143:    floating point exception handling You can check which
144:    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
145:    (usually at /usr/include/bits/fenv.h) for the enum values on your system.

147:    Caution:
148:    On certain machines, in particular the IBM PowerPC, floating point
149:    trapping may be VERY slow!

151: .seealso: PetscFPTrapPush(), PetscFPTrapPop(), PetscDetermineInitialFPTrap()
152: @*/
153: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
154: {
155:   char *out;

157:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
158:   (void) ieee_flags("clear","exception","all",&out);
159:   if (flag == PETSC_FP_TRAP_ON) {
160:     /*
161:       To trap more fp exceptions, including underflow, change the line below to
162:       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
163:     */
164:     if (ieee_handler("set","common",PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
165:   } else if (ieee_handler("clear","common",PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");

167:   _trapmode = flag;
168:   return 0;
169: }

171: /*@
172:    PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when PetscInitialize() is called

174:    Not Collective

176:    Notes:
177:       Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on.

179:    Level: advanced

181: .seealso: PetscFPTrapPush(), PetscFPTrapPop(), PetscDetermineInitialFPTrap()
182: @*/
183: PetscErrorCode  PetscDetermineInitialFPTrap(void)
184: {
185:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
186:   return 0;
187: }

189: /* -------------------------------------------------------------------------------------------*/
190: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
191: #include <sunmath.h>
192: #include <floatingpoint.h>
193: #include <siginfo.h>
194: #include <ucontext.h>

196: static struct { int code_no; char *name; } error_codes[] = {
197:   { FPE_FLTINV,"invalid floating point operand"},
198:   { FPE_FLTRES,"inexact floating point result"},
199:   { FPE_FLTDIV,"division-by-zero"},
200:   { FPE_FLTUND,"floating point underflow"},
201:   { FPE_FLTOVF,"floating point overflow"},
202:   { 0,         "unknown error"}
203: };
204: #define SIGPC(scp) (scp->si_addr)

206: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
207: {
208:   int err_ind = -1,code = scp->si_code;

210:   for (int j = 0; error_codes[j].code_no; j++) {
211:     if (error_codes[j].code_no == code) err_ind = j;
212:   }

214:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
215:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));

217:   (void)PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
218:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
219: }

221: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
222: {
223:   char *out;

225:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
226:   (void) ieee_flags("clear","exception","all",&out);
227:   if (flag == PETSC_FP_TRAP_ON) {
228:     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
229:   } else {
230:     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
231:   }
232:   _trapmode = flag;
233:   return 0;
234: }

236: PetscErrorCode  PetscDetermineInitialFPTrap(void)
237: {
238:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
239:   return 0;
240: }

242: /* ------------------------------------------------------------------------------------------*/
243: #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
244: #include <sigfpe.h>
245: static struct { int code_no; char *name; } error_codes[] = {
246:   { _INVALID   ,"IEEE operand error" },
247:   { _OVERFL    ,"floating point overflow" },
248:   { _UNDERFL   ,"floating point underflow" },
249:   { _DIVZERO   ,"floating point divide" },
250:   { 0          ,"unknown error" }
251: } ;
252: void PetscDefaultFPTrap(unsigned exception[],int val[])
253: {
254:   int err_ind = -1,code = exception[0];

256:   for (int j = 0; error_codes[j].code_no; j++) {
257:     if (error_codes[j].code_no == code) err_ind = j;
258:   }
259:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
260:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);

262:   (void)PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
263:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
264: }

266: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
267: {
268:   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON,,_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
269:   else                          handle_sigfpes(_OFF,_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
270:   _trapmode = flag;
271:   return 0;
272: }

274: PetscErrorCode  PetscDetermineInitialFPTrap(void)
275: {
276:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
277:   return 0;
278: }

280: /* -------------------------------------------------------------------------------------------*/
281: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
282: #include <sunmath.h>
283: #include <floatingpoint.h>
284: #include <siginfo.h>
285: #include <ucontext.h>

287: static struct { int code_no; char *name; } error_codes[] = {
288:   { FPE_FLTINV,"invalid floating point operand"},
289:   { FPE_FLTRES,"inexact floating point result"},
290:   { FPE_FLTDIV,"division-by-zero"},
291:   { FPE_FLTUND,"floating point underflow"},
292:   { FPE_FLTOVF,"floating point overflow"},
293:   { 0,         "unknown error"}
294: };
295: #define SIGPC(scp) (scp->si_addr)

297: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
298: {
299:   int err_ind = -1,code = scp->si_code;

301:   err_ind = -1;
302:   for (int j = 0; error_codes[j].code_no; j++) {
303:     if (error_codes[j].code_no == code) err_ind = j;
304:   }

306:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
307:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));

309:   (void)PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
310:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
311: }

313: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
314: {
315:   char *out;

317:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
318:   (void) ieee_flags("clear","exception","all",&out);
319:   if (flag == PETSC_FP_TRAP_ON) {
320:     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
321:   } else {
322:     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
323:   }
324:   _trapmode = flag;
325:   return 0;
326: }

328: PetscErrorCode  PetscDetermineInitialFPTrap(void)
329: {
330:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
331:   return 0;
332: }

334: /*----------------------------------------------- --------------------------------------------*/
335: #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
336: /* In "fast" mode, floating point traps are imprecise and ignored.
337:    This is the reason for the fptrap(FP_TRAP_SYNC) call */
338: struct sigcontext;
339: #include <fpxcp.h>
340: #include <fptrap.h>
341: #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
342: #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
343: #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
344: #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
345: #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)

347: static struct { int code_no; char *name; } error_codes[] = {
348:   {FPE_FLTOPERR_TRAP   ,"IEEE operand error" },
349:   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
350:   { FPE_FLTUND_TRAP    ,"floating point underflow" },
351:   { FPE_FLTDIV_TRAP    ,"floating point divide" },
352:   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
353:   { 0                  ,"unknown error" }
354: } ;
355: #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
356: /*
357:    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
358:    it looks like it should from the include definitions.  It is probably
359:    some strange interaction with the "POSIX_SOURCE" that we require.
360: */

362: void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
363: {
365:   int            err_ind,j;
366:   fp_ctx_t       flt_context;

368:   fp_sh_trap_info(scp,&flt_context);

370:   err_ind = -1;
371:   for (j = 0; error_codes[j].code_no; j++) {
372:     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
373:   }

375:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
376:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);

378:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
379:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
380: }

382: PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
383: {
384:   if (on == PETSC_FP_TRAP_ON) {
385:     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
386:     fp_trap(FP_TRAP_SYNC);
387:     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
388:     /* fp_enable(mask) for individual traps.  Values are:
389:        TRP_INVALID
390:        TRP_DIV_BY_ZERO
391:        TRP_OVERFLOW
392:        TRP_UNDERFLOW
393:        TRP_INEXACT
394:        Can OR then together.
395:        fp_enable_all(); for all traps.
396:     */
397:   } else {
398:     signal(SIGFPE,SIG_DFL);
399:     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW);
400:     fp_trap(FP_TRAP_OFF);
401:   }
402:   _trapmode = on;
403:   return 0;
404: }

406: PetscErrorCode  PetscDetermineInitialFPTrap(void)
407: {
408:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
409:   return 0;
410: }

412: /* ------------------------------------------------------------*/
413: #elif defined(PETSC_HAVE_WINDOWS_COMPILERS)
414: #include <float.h>
415: void PetscDefaultFPTrap(int sig)
416: {
417:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
418:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
419:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
420: }

422: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
423: {
424:   unsigned int cw;

426:   if (on == PETSC_FP_TRAP_ON) {
427:     cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW;
429:   } else {
430:     cw = 0;
432:   }
433:   (void)_controlfp(0, cw);
434:   _trapmode = on;
435:   return 0;
436: }

438: PetscErrorCode  PetscDetermineInitialFPTrap(void)
439: {
440:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
441:   return 0;
442: }

444: /* ------------------------------------------------------------*/
445: #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
446: /*
447:    C99 style floating point environment.

449:    Note that C99 merely specifies how to save, restore, and clear the floating
450:    point environment as well as defining an enumeration of exception codes.  In
451:    particular, C99 does not specify how to make floating point exceptions raise
452:    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
453:    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
454: */
455: #include <fenv.h>
456: typedef struct {int code; const char *name;} FPNode;
457: static const FPNode error_codes[] = {
458:   {FE_DIVBYZERO,"divide by zero"},
459:   {FE_INEXACT,  "inexact floating point result"},
460:   {FE_INVALID,  "invalid floating point arguments (domain error)"},
461:   {FE_OVERFLOW, "floating point overflow"},
462:   {FE_UNDERFLOW,"floating point underflow"},
463:   {0           ,"unknown error"}
464: };

466: void PetscDefaultFPTrap(int sig)
467: {
468:   const FPNode *node;
469:   int          code;
470:   PetscBool    matched = PETSC_FALSE;

472:   /* Note: While it is possible for the exception state to be preserved by the
473:    * kernel, this seems to be rare which makes the following flag testing almost
474:    * useless.  But on a system where the flags can be preserved, it would provide
475:    * more detail.
476:    */
477:   code = fetestexcept(FE_ALL_EXCEPT);
478:   for (node=&error_codes[0]; node->code; node++) {
479:     if (code & node->code) {
480:       matched = PETSC_TRUE;
481:       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
482:       code &= ~node->code; /* Unset this flag since it has been processed */
483:     }
484:   }
485:   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
486:     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
487:     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
488:     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
489:     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
490:     (*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);
491:   }

493:   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
494: #if PetscDefined(USE_DEBUG)
495:   (*PetscErrorPrintf)("likely location of problem given in stack below\n");
496:   (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
497:   PetscStackView(PETSC_STDOUT);
498: #else
499:   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
500:   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
501: #endif
502:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
503:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
504: }

506: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
507: {
508:   if (on == PETSC_FP_TRAP_ON) {
509:     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
511: #if defined(FE_NOMASK_ENV)
512:     /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
514: #elif defined PETSC_HAVE_XMMINTRIN_H
515:    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO);
516:    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW);
517:    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW);
518:    _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
519: #else
520:     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
521: #endif
523:   } else {
525:     /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */
527:   }
528:   _trapmode = on;
529:   return 0;
530: }

532: PetscErrorCode  PetscDetermineInitialFPTrap(void)
533: {
534: #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
535:   unsigned int flags;
536: #endif

538: #if defined(FE_NOMASK_ENV)
539:   flags = fegetexcept();
540:   if (flags & FE_DIVBYZERO) {
541: #elif defined PETSC_HAVE_XMMINTRIN_H
542:   flags = _MM_GET_EXCEPTION_MASK();
543:   if (!(flags & _MM_MASK_DIV_ZERO)) {
544: #else
545:   PetscInfo(NULL,"Floating point trapping unknown, assuming off\n");
546:   return 0;
547: #endif
548: #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H
549:     _trapmode = PETSC_FP_TRAP_ON;
550:     PetscInfo(NULL,"Floating point trapping is on by default %d\n",flags);
551:   } else {
552:     _trapmode = PETSC_FP_TRAP_OFF;
553:     PetscInfo(NULL,"Floating point trapping is off by default %d\n",flags);
554:   }
555:   return 0;
556: #endif
557: }

559: /* ------------------------------------------------------------*/
560: #elif defined(PETSC_HAVE_IEEEFP_H)
561: #include <ieeefp.h>
562: void PetscDefaultFPTrap(int sig)
563: {
564:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
565:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
566:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
567: }

569: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
570: {
571:   if (on == PETSC_FP_TRAP_ON) {
572: #if defined(PETSC_HAVE_FPPRESETSTICKY)
573:     fpresetsticky(fpgetsticky());
574: #elif defined(PETSC_HAVE_FPSETSTICKY)
575:     fpsetsticky(fpgetsticky());
576: #endif
577:     fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL |  FP_X_OFL);
579:   } else {
580: #if defined(PETSC_HAVE_FPPRESETSTICKY)
581:     fpresetsticky(fpgetsticky());
582: #elif defined(PETSC_HAVE_FPSETSTICKY)
583:     fpsetsticky(fpgetsticky());
584: #endif
585:     fpsetmask(0);
587:   }
588:   _trapmode = on;
589:   return 0;
590: }

592: PetscErrorCode  PetscDetermineInitialFPTrap(void)
593: {
594:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
595:   return 0;
596: }

598: /* -------------------------Default -----------------------------------*/
599: #else

601: void PetscDefaultFPTrap(int sig)
602: {
603:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
604:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
605:   PETSCABORT(MPI_COMM_WORLD,PETSC_ERR_FP);
606: }

608: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
609: {
610:   if (on == PETSC_FP_TRAP_ON) {
611:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
612:   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");

614:   _trapmode = on;
615:   return 0;
616: }

618: PetscErrorCode  PetscDetermineInitialFPTrap(void)
619: {
620:   PetscInfo(NULL,"Unable to determine initial floating point trapping. Assuming it is off\n");
621:   return 0;
622: }
623: #endif