G4FPEDetection.hh

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id$
00028 //
00029 // 
00030 // -*- C++ -*-
00031 //
00032 // -----------------------------------------------------------------------
00033 // This global method should be used on LINUX or MacOSX platforms with gcc
00034 // compiler for activating NaN detection and FPE signals, and forcing
00035 // abortion of the application at the time these are detected.
00036 // Meant to be used for debug purposes, can be activated by compiling the
00037 // "run" module with the flag G4FPE_DEBUG set in the environment.
00038 // -----------------------------------------------------------------------
00039 
00040 #ifndef G4FPEDetection_h
00041 #define G4FPEDetection_h 1
00042 
00043 #include <iostream>
00044 #include <stdlib.h>  /* abort(), exit() */
00045 
00046 #ifdef __linux__
00047 #ifdef __GNUC__
00048   #include <features.h>
00049   #include <fenv.h>
00050   #include <csignal>
00051 
00052   struct sigaction termaction, oldaction;
00053 
00054   static void TerminationSignalHandler(int sig, siginfo_t* sinfo, void* /* context */)
00055   {
00056     std::cerr << "ERROR: " << sig;
00057     std::string message = "Floating-point exception (FPE).";
00058 
00059     if (sinfo) {
00060       switch (sinfo->si_code) {
00061 #ifdef FPE_NOOP         /* BUG: MacOSX uses this instead of INTDIV */
00062       case FPE_NOOP:
00063 #endif
00064       case FPE_INTDIV:
00065         message = "Integer divide by zero.";
00066         break;
00067       case FPE_INTOVF:
00068         message = "Integer overflow.";
00069         break;
00070       case FPE_FLTDIV:
00071         message = "Floating point divide by zero.";
00072         break;
00073       case FPE_FLTOVF:
00074         message = "Floating point overflow.";
00075         break;
00076       case FPE_FLTUND:
00077         message = "Floating point underflow.";
00078         break;
00079       case FPE_FLTRES:
00080         message = "Floating point inexact result.";
00081         break;
00082       case FPE_FLTINV:
00083         message = "Floating point invalid operation.";
00084         break;
00085       case FPE_FLTSUB:
00086         message = "Subscript out of range.";
00087         break;
00088       default:
00089         message = "Unknown error.";
00090         break;
00091       }
00092     }
00093 
00094     std::cerr << " - " << message << std::endl;
00095     
00096     ::abort();
00097   }
00098 
00099   static void InvalidOperationDetection()
00100   {
00101     std::cout << std::endl
00102               << "        "
00103               << "############################################" << std::endl
00104               << "        "
00105               << "!!! WARNING - FPE detection is activated !!!" << std::endl
00106               << "        "
00107               << "############################################" << std::endl;
00108 
00109     (void) feenableexcept( FE_DIVBYZERO );
00110     (void) feenableexcept( FE_INVALID );
00111     //(void) feenableexcept( FE_OVERFLOW );
00112     //(void) feenableexcept( FE_UNDERFLOW );
00113 
00114     sigdelset(&termaction.sa_mask,SIGFPE);
00115     termaction.sa_sigaction=TerminationSignalHandler;
00116     termaction.sa_flags=SA_SIGINFO;
00117     sigaction(SIGFPE, &termaction, &oldaction);
00118   }
00119 #endif
00120 #elif __MACH__      /* MacOSX */
00121 
00122   #include <fenv.h>
00123   #include <signal.h>
00124 
00125   #define DEFINED_PPC      (defined(__ppc__) || defined(__ppc64__))
00126   #define DEFINED_INTEL    (defined(__i386__) || defined(__x86_64__))
00127 
00128   #if DEFINED_PPC
00129 
00130     #define FE_EXCEPT_SHIFT 22  // shift flags right to get masks
00131     #define FM_ALL_EXCEPT    FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT 
00132 
00133     static inline int feenableexcept (unsigned int excepts)
00134     {
00135       static fenv_t fenv;
00136       unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
00137                    old_excepts;  // all previous masks
00138 
00139       if ( fegetenv (&fenv) )  { return -1; }
00140       old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
00141       fenv = (fenv & ~new_excepts) | new_excepts;
00142 
00143       return ( fesetenv (&fenv) ? -1 : old_excepts );
00144     }
00145 
00146     static inline int fedisableexcept (unsigned int excepts)
00147     {
00148       static fenv_t fenv;
00149       unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
00150                    old_excepts;  // previous masks
00151 
00152       if ( fegetenv (&fenv) )  { return -1; }
00153       old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
00154       fenv &= still_on;
00155 
00156       return ( fesetenv (&fenv) ? -1 : old_excepts );
00157     }
00158 
00159   #elif DEFINED_INTEL
00160 
00161     static inline int feenableexcept (unsigned int excepts)
00162     {
00163       static fenv_t fenv;
00164       unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
00165                    old_excepts;  // previous masks
00166 
00167       if ( fegetenv (&fenv) )  { return -1; }
00168       old_excepts = fenv.__control & FE_ALL_EXCEPT;
00169 
00170       // unmask
00171       //
00172       fenv.__control &= ~new_excepts;
00173       fenv.__mxcsr   &= ~(new_excepts << 7);
00174 
00175       return ( fesetenv (&fenv) ? -1 : old_excepts );
00176     }
00177 
00178     static inline int fedisableexcept (unsigned int excepts)
00179     {
00180       static fenv_t fenv;
00181       unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
00182                    old_excepts;  // all previous masks
00183 
00184       if ( fegetenv (&fenv) )  { return -1; }
00185       old_excepts = fenv.__control & FE_ALL_EXCEPT;
00186 
00187       // mask
00188       //
00189       fenv.__control |= new_excepts;
00190       fenv.__mxcsr   |= new_excepts << 7;
00191 
00192       return ( fesetenv (&fenv) ? -1 : old_excepts );
00193     }
00194 
00195   #endif  /* PPC or INTEL enabling */
00196 
00197   static void TerminationSignalHandler(int sig, siginfo_t* sinfo, void* /* context */)
00198   {
00199     std::cerr << "ERROR: " << sig;
00200     std::string message = "Floating-point exception (FPE).";
00201 
00202     if (sinfo) {
00203       switch (sinfo->si_code) {
00204 #ifdef FPE_NOOP         /* BUG: MacOSX uses this instead of INTDIV */
00205       case FPE_NOOP:
00206 #endif
00207       case FPE_INTDIV:
00208         message = "Integer divide by zero.";
00209         break;
00210       case FPE_INTOVF:
00211         message = "Integer overflow.";
00212         break;
00213       case FPE_FLTDIV:
00214         message = "Floating point divide by zero.";
00215         break;
00216       case FPE_FLTOVF:
00217         message = "Floating point overflow.";
00218         break;
00219       case FPE_FLTUND:
00220         message = "Floating point underflow.";
00221         break;
00222       case FPE_FLTRES:
00223         message = "Floating point inexact result.";
00224         break;
00225       case FPE_FLTINV:
00226         message = "Floating point invalid operation.";
00227         break;
00228       case FPE_FLTSUB:
00229         message = "Subscript out of range.";
00230         break;
00231       default:
00232         message = "Unknown error.";
00233         break;
00234       }
00235     }
00236 
00237     std::cerr << " - " << message << std::endl;
00238     
00239     ::abort();
00240   }
00241 
00242   static void InvalidOperationDetection()
00243   {
00244     struct sigaction termaction, oldaction;
00245 
00246     std::cout << std::endl
00247               << "        "
00248               << "############################################" << std::endl
00249               << "        "
00250               << "!!! WARNING - FPE detection is activated !!!" << std::endl
00251               << "        "
00252               << "############################################" << std::endl;
00253 
00254     feenableexcept ( FE_DIVBYZERO );
00255     feenableexcept ( FE_INVALID   );
00256     // fedisableexcept( FE_OVERFLOW  );
00257     // fedisableexcept( FE_UNDERFLOW );
00258 
00259     sigdelset(&termaction.sa_mask,SIGFPE);
00260     termaction.sa_sigaction=TerminationSignalHandler;
00261     termaction.sa_flags=SA_SIGINFO;
00262     sigaction(SIGFPE, &termaction, &oldaction);
00263   }
00264 #else  /* Not Linux, nor MacOSX ... */
00265 
00266   static void InvalidOperationDetection() {;}
00267 
00268 #endif
00269 
00270 #endif

Generated on Mon May 27 17:48:17 2013 for Geant4 by  doxygen 1.4.7