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