Actual source code: fp.c

      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
     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"

     16: /*--------------------------------------- ---------------------------------------------------*/
     17: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
     18: #include <floatingpoint.h>

     21: PetscErrorCode ieee_flags(char*,char*,char*,char**);
     22: PetscErrorCode ieee_handler(char *,char *,sigfpe_handler_type(int,int,struct sigcontext*,char *));

     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)

     38: sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
     39: {
     41:   int err_ind = -1,j;

     44:   for (j = 0 ; error_codes[j].code_no ; j++) {
     45:     if (error_codes[j].code_no == code) err_ind = j;
     46:   }

     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:   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:   return(0);
     56: }

     60: /*@C
     61:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
     62:                     This option may not work on certain machines.

     64:    Not Collective

     66:    Input Parameters:
     67: .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.

     69:    Options Database Keys:
     70: .  -fp_trap - Activates floating point trapping

     72:    Level: advanced

     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.

     79:    Caution:
     80:    On certain machines, in particular the IBM rs6000, floating point
     81:    trapping is VERY slow!

     83:    Concepts: floating point exceptions^trapping
     84:    Concepts: divide by zero

     86: @*/
     87: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
     88: {
     89:   char *out;

     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:   return(0);
    108: }

    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>

    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)

    129: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
    130: {
    131:   int err_ind,j,code = scp->si_code;

    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:   }

    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:   PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
    146:   MPI_Abort(PETSC_COMM_WORLD,0);
    147: }

    151: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
    152: {
    153:   char *out;

    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:   return(0);
    168: }

    170: /* ------------------------------------------------------------------------------------------*/

    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: } ;
    183: void PetscDefaultFPTrap(unsigned exception[],int val[])
    184: {
    185:   int err_ind,j,code;

    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: }

    204: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
    205: {
    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:   return(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)

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

    245: void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
    246: {
    248:   int      err_ind,j;
    249:   fp_ctx_t flt_context;

    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:   }

    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:   PetscError(0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
    265:   MPI_Abort(PETSC_COMM_WORLD,0);
    266: }

    270: PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
    271: {
    272:   int flag;

    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:   return(0);
    294: }

    296: /* -------------------------Default -----------------------------------*/
    297: #else
    298: struct PETSCERRORCODES { int code_no; const char *name; } error_codes[] = {
    299:            { 0                ,"unknown error" }
    300: } ;
    304: void PetscDefaultFPTrap(int sig)
    305: {
    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: }
    314: PetscErrorCode PETSC_DLLEXPORT PetscSetFPTrap(PetscFPTrap on)
    315: {
    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:   return(0);
    327: }
    328: #endif