xref: /petsc/src/sys/error/fp.c (revision 2bb461577434904307fe4f3c85c76e48e26c0c26)
1 #define PETSC_DLL
2 /*
3 *	IEEE error handler for all machines. Since each machine has
4 *   enough slight differences we have completely separate codes for each one.
5 *
6 */
7 #include "petsc.h"           /*I  "petsc.h"  I*/
8 #include "petscsys.h"
9 #include <signal.h>
10 #if defined(PETSC_HAVE_STDLIB_H)
11 #include <stdlib.h>
12 #endif
13 #include "petscfix.h"
14 
15 
16 /*--------------------------------------- ---------------------------------------------------*/
17 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
18 #include <floatingpoint.h>
19 
20 EXTERN_C_BEGIN
21 PetscErrorCode ieee_flags(char*,char*,char*,char**);
22 PetscErrorCode ieee_handler(char *,char *,sigfpe_handler_type(int,int,struct sigcontext*,char *));
23 EXTERN_C_END
24 
25 struct { int code_no; char *name; } error_codes[] = {
26            { FPE_INTDIV_TRAP	,"integer divide" },
27 	   { FPE_FLTOPERR_TRAP	,"IEEE operand error" },
28 	   { FPE_FLTOVF_TRAP	,"floating point overflow" },
29 	   { FPE_FLTUND_TRAP	,"floating point underflow" },
30 	   { FPE_FLTDIV_TRAP	,"floating pointing divide" },
31 	   { FPE_FLTINEX_TRAP	,"inexact floating point result" },
32 	   { 0			,"unknown error" }
33 } ;
34 #define SIGPC(scp) (scp->sc_pc)
35 
36 #undef __FUNCT__
37 #define __FUNCT__ "PetscDefaultFPTrap"
38 sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
39 {
40   PetscErrorCode ierr;
41   int err_ind = -1,j;
42 
43   PetscFunctionBegin;
44   for (j = 0 ; error_codes[j].code_no ; j++) {
45     if (error_codes[j].code_no == code) err_ind = j;
46   }
47 
48   if (err_ind >= 0) {
49     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
50   } else {
51     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
52   }
53   ierr = PetscError(PETSC_ERR_FP,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
54   MPI_Abort(PETSC_COMM_WORLD,0);
55   PetscFunctionReturn(0);
56 }
57 
58 #undef __FUNCT__
59 #define __FUNCT__ "PetscSetFPTrap"
60 /*@C
61    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
62                     This option may not work on certain machines.
63 
64    Not Collective
65 
66    Input Parameters:
67 .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.
68 
69    Options Database Keys:
70 .  -fp_trap - Activates floating point trapping
71 
72    Level: advanced
73 
74    Description:
75    On systems that support it, this routine causes floating point
76    overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to
77    cause a message to be printed and the program to exit.
78 
79    Caution:
80    On certain machines, in particular the IBM rs6000, floating point
81    trapping is VERY slow!
82 
83    Concepts: floating point exceptions^trapping
84    Concepts: divide by zero
85 
86 @*/
87 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
88 {
89   char *out;
90 
91   PetscFunctionBegin;
92   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
93   (void) ieee_flags("clear","exception","all",&out);
94   if (flag == PETSC_FP_TRAP_ON) {
95     if (ieee_handler("set","common",PetscDefaultFPTrap)) {
96       /*
97         To trap more fp exceptions, including undrflow, change the above line to
98         if (ieee_handler("set","all",PetscDefaultFPTrap)) {
99       */
100       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
101     }
102   } else {
103     if (ieee_handler("clear","common",PetscDefaultFPTrap)) {
104       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
105     }
106   }
107   PetscFunctionReturn(0);
108 }
109 
110 /* -------------------------------------------------------------------------------------------*/
111 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
112 #include <sunmath.h>
113 #include <floatingpoint.h>
114 #include <siginfo.h>
115 #include <ucontext.h>
116 
117 struct { int code_no; char *name; } error_codes[] = {
118   {  FPE_FLTINV,"invalid floating point operand"},
119   {  FPE_FLTRES,"inexact floating point result"},
120   {  FPE_FLTDIV,"division-by-zero"},
121   {  FPE_FLTUND,"floating point underflow"},
122   {  FPE_FLTOVF,"floating point overflow"},
123   {  0,         "unknown error"}
124 };
125 #define SIGPC(scp) (scp->si_addr)
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "PetscDefaultFPTrap"
129 void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
130 {
131   int err_ind,j,code = scp->si_code;
132   PetscErrorCode ierr;
133 
134   PetscFunctionBegin;
135   err_ind = -1 ;
136   for (j = 0 ; error_codes[j].code_no ; j++) {
137     if (error_codes[j].code_no == code) err_ind = j;
138   }
139 
140   if (err_ind >= 0) {
141     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
142   } else {
143     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
144   }
145   ierr = PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
146   MPI_Abort(PETSC_COMM_WORLD,0);
147 }
148 
149 #undef __FUNCT__
150 #define __FUNCT__ "PetscSetFPTrap"
151 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
152 {
153   char *out;
154 
155   PetscFunctionBegin;
156   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
157   (void) ieee_flags("clear","exception","all",&out);
158   if (flag == PETSC_FP_TRAP_ON) {
159     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
160       (*PetscErrorPrintf)("Can't set floating point handler\n");
161     }
162   } else {
163     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
164      (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
165     }
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 /* ------------------------------------------------------------------------------------------*/
171 
172 #elif defined (PETSC_HAVE_IRIX_STYLE_FPTRAP)
173 #include <sigfpe.h>
174 struct { int code_no; char *name; } error_codes[] = {
175        { _INVALID   ,"IEEE operand error" },
176        { _OVERFL    ,"floating point overflow" },
177        { _UNDERFL   ,"floating point underflow" },
178        { _DIVZERO   ,"floating point divide" },
179        { 0          ,"unknown error" }
180 } ;
181 #undef __FUNCT__
182 #define __FUNCT__ "PetscDefaultFPTrap"
183 void PetscDefaultFPTrap(unsigned exception[],int val[])
184 {
185   int err_ind,j,code;
186 
187   PetscFunctionBegin;
188   code = exception[0];
189   err_ind = -1 ;
190   for (j = 0 ; error_codes[j].code_no ; j++){
191     if (error_codes[j].code_no == code) err_ind = j;
192   }
193   if (err_ind >= 0){
194     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
195   } else{
196     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);
197   }
198   PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
199   MPI_Abort(PETSC_COMM_WORLD,0);
200 }
201 
202 #undef __FUNCT__
203 #define __FUNCT__ "PetscSetFPTrap"
204 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
205 {
206   PetscFunctionBegin;
207   if (flag == PETSC_FP_TRAP_ON) {
208     handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
209   } else {
210     handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
211   }
212   PetscFunctionReturn(0);
213 }
214 /*----------------------------------------------- --------------------------------------------*/
215 /* In "fast" mode, floating point traps are imprecise and ignored.
216    This is the reason for the fptrap(FP_TRAP_SYNC) call */
217 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
218 struct sigcontext;
219 #include <fpxcp.h>
220 #include <fptrap.h>
221 #include <stdlib.h>
222 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
223 #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
224 #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
225 #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
226 #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)
227 
228 struct { int code_no; char *name; } error_codes[] = {
229            {FPE_FLTOPERR_TRAP	,"IEEE operand error" },
230 	   { FPE_FLTOVF_TRAP	,"floating point overflow" },
231 	   { FPE_FLTUND_TRAP	,"floating point underflow" },
232 	   { FPE_FLTDIV_TRAP	,"floating point divide" },
233 	   { FPE_FLTINEX_TRAP	,"inexact floating point result" },
234 	   { 0			,"unknown error" }
235 } ;
236 #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
237 /*
238    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
239    it looks like it should from the include definitions.  It is probably
240    some strange interaction with the "POSIX_SOURCE" that we require.
241 */
242 
243 #undef __FUNCT__
244 #define __FUNCT__ "PetscDefaultFPTrap"
245 void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
246 {
247   PetscErrorCode ierr;
248   int      err_ind,j;
249   fp_ctx_t flt_context;
250 
251   PetscFunctionBegin;
252   fp_sh_trap_info(scp,&flt_context);
253 
254   err_ind = -1 ;
255   for (j = 0 ; error_codes[j].code_no ; j++) {
256     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
257   }
258 
259   if (err_ind >= 0){
260     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
261   } else{
262     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
263   }
264   ierr = PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
265   MPI_Abort(PETSC_COMM_WORLD,0);
266 }
267 
268 #undef __FUNCT__
269 #define __FUNCT__ "PetscSetFPTrap"
270 PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
271 {
272   int flag;
273 
274   PetscFunctionBegin;
275   if (on == PETSC_FP_TRAP_ON) {
276     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
277     fp_trap(FP_TRAP_SYNC);
278     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
279     /* fp_enable(mask) for individual traps.  Values are:
280        TRP_INVALID
281        TRP_DIV_BY_ZERO
282        TRP_OVERFLOW
283        TRP_UNDERFLOW
284        TRP_INEXACT
285        Can OR then together.
286        fp_enable_all(); for all traps.
287     */
288   } else {
289     signal(SIGFPE,SIG_DFL);
290     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
291     fp_trap(FP_TRAP_OFF);
292   }
293   PetscFunctionReturn(0);
294 }
295 
296 /* -------------------------Default -----------------------------------*/
297 #else
298 struct PETSCERRORCODES { int code_no; const char *name; } error_codes[] = {
299 	   { 0		,"unknown error" }
300 } ;
301 EXTERN_C_BEGIN
302 #undef __FUNCT__
303 #define __FUNCT__ "PetscDefaultFPTrap"
304 void PetscDefaultFPTrap(int sig)
305 {
306   PetscFunctionBegin;
307   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
308   PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
309   MPI_Abort(PETSC_COMM_WORLD,0);
310 }
311 EXTERN_C_END
312 #undef __FUNCT__
313 #define __FUNCT__ "PetscSetFPTrap"
314 PetscErrorCode PETSC_DLLEXPORT PetscSetFPTrap(PetscFPTrap on)
315 {
316   PetscFunctionBegin;
317   if (on == PETSC_FP_TRAP_ON) {
318     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) {
319       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
320     }
321   } else {
322     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) {
323       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
324     }
325   }
326   PetscFunctionReturn(0);
327 }
328 #endif
329 
330 
331 
332