Post by Generic Usenet AccountThanks to all of you who proposed using setjmp and longjmp, in
conjunction with SIGFPE for handling floating exceptions. It was a
little more involved than I thought due to getting into an infinite
loop, with the signal handler being called endlessly called once the
SIG_FPE exception occurs. I have posted my implementation to
comp.sources.d.
Here it goes ....
/////////////////// Header File ///////////
#ifndef _FPEHANDLER_H_
#define _FPEHANDLER_H_
#include <pthread.h>
#include <setjmp.h>
#include <stdexcept>
#include <stack>
using namespace std;
/////////////////////////////////////////////////////////////////////
//
// Floating Point Error Handler class
//
/////////////////////////////////////////////////////////////////////
class FPEHandler
{
public:
virtual ~FPEHandler();
static FPEHandler& instance();
void provideLastBuf(jmp_buf& jb) throw (runtime_error);
jmp_buf* openFPOLocation();
bool closeFPOLocation(const jmp_buf* jbPtr);
jmp_buf* lastFPOLocation();
protected:
FPEHandler();
static FPEHandler* _instance;
pthread_mutex_t _mutex;
stack<jmp_buf*> _fpLocLIFO; // floating point location
LIFO
};
#endif //_FPEHANDLER_H_
////////////// Source File ////////////////
#include "FPEHandler.h"
#include <iostream>
#include <sstream>
#include <sys/time.h>
using namespace std;
//
// ---------------Defining static variables---------------------------
//
FPEHandler* FPEHandler::_instance = new FPEHandler();
/////////////////////////////////////////////////////////////////////////
FPEHandler::FPEHandler()
{
#ifdef TRACE
cout << "Creating FPEHandler object" << endl;
#endif
// Initialize the mutex attribute
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
attr.__mutexkind = PTHREAD_MUTEX_RECURSIVE_NP;
// Initialize the mutex
pthread_mutex_init(&_mutex,&attr);
}
/////////////////////////////////////////////////////////////////////////
FPEHandler::~FPEHandler()
{
#ifdef TRACE
cout << "Deleting FPEHandler object" << endl;
#endif
// Lock the mutex
if(pthread_mutex_lock(&_mutex))
{
throw runtime_error(strerror(errno));
}
while(!_fpLocLIFO.empty()) _fpLocLIFO.pop();
// Destroy the mutex
if(pthread_mutex_destroy(&_mutex))
{
throw runtime_error(strerror(errno));
}
}
/////////////////////////////////////////////////////////////////////////
FPEHandler&
FPEHandler::instance()
{
if(_instance == NULL)
_instance = new FPEHandler;
return *_instance;
}
/////////////////////////////////////////////////////////////////////////
jmp_buf*
FPEHandler::openFPOLocation()
{
jmp_buf* jbPtr = NULL;
// Lock the mutex
if(pthread_mutex_lock(&_mutex))
{
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
return jbPtr;
}
jbPtr = (jmp_buf *) malloc(sizeof(jmp_buf));
_fpLocLIFO.push(jbPtr);
#ifdef DEBUG
cout << "Currently " << _fpLocLIFO.size() << " entries in the LIFO
\n";
#endif // DEBUG
// Unlock the mutex
if(pthread_mutex_unlock(&_mutex))
{
free (jbPtr);
jbPtr = NULL;
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
}
return jbPtr;
}
/////////////////////////////////////////////////////////////////////////
bool
FPEHandler::closeFPOLocation(const jmp_buf*)
{
bool retVal = false;
// Currently because of the stack implementation, the input
parameter
// is not used. At some future point we may consider getting rid of
this
// parameter altogether (although then the API will no longer follow
the
// STDIO File I/O API)
// Lock the mutex
if(pthread_mutex_lock(&_mutex))
{
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
return retVal;
}
if(!_fpLocLIFO.empty())
{
retVal = true;
_fpLocLIFO.pop();
#ifdef DEBUG
cout << _fpLocLIFO.size() << " entries left in the LIFO\n";
#endif // DEBUG
}
// Unlock the mutex
if(pthread_mutex_unlock(&_mutex))
{
retVal = false;
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////
jmp_buf*
FPEHandler::lastFPOLocation()
{
jmp_buf *jbPtr = NULL;
// Lock the mutex
if(pthread_mutex_lock(&_mutex))
{
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
return jbPtr;
}
if(!_fpLocLIFO.empty())
{
jbPtr = _fpLocLIFO.top();
}
// Unlock the mutex
if(pthread_mutex_unlock(&_mutex))
{
jbPtr = NULL;
cerr << "File: " << __FILE__ << ", Line: " << __LINE__ << ",
Function: "
<< __func__ << "()\n";
cerr << strerror(errno) << endl;
}
return jbPtr;
}
/////////// Driver File /////////////////
#include <signal.h>
#include <stdexcept>
#include "FPEHandler.h"
#include <iostream>
using namespace std;
/* Traditional UNIX Signal Handling */
typedef void sigfunc_trad(int);
sigfunc_trad * sig_install_trad(int, sigfunc_trad*);
/* Real-time UNIX Signal Handling (POSIX) */
typedef void sigfunc_rt(int, siginfo_t*, void*);
sigfunc_rt * sig_install_rt(int, sigfunc_rt*);
sigfunc_rt * sig_install(int, sigfunc_rt*);
/////////////////////////////////////////////////////////////////////////
//
// Traditional Signal Installer
//
/////////////////////////////////////////////////////////////////////////
sigfunc_trad *
sig_install_trad(int signo, sigfunc_trad *func)
{
sigfunc_trad *sigfunc = SIG_IGN;
if(signal(signo, func) != SIG_IGN)
sigfunc = signal(signo, func);
return sigfunc;
}
/////////////////////////////////////////////////////////////////////////
//
// Real Time Signal Installer (POSIX)
//
/////////////////////////////////////////////////////////////////////////
sigfunc_rt *
sig_install_rt(int signo, sigfunc_rt *func)
{
sigfunc_rt *sigfunc;
struct sigaction act, oact;
act.sa_sigaction = func; /* must store function addr here */
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO; /* must specify this for realtime */
if (sigaction(signo, &act, &oact) < 0)
{
sigfunc = (sigfunc_rt *) SIG_ERR;
#ifdef DEBUG
cerr << "sig_install error\n";
#endif // DEBUG
}
else
sigfunc = oact.sa_sigaction;
return sigfunc;
}
/////////////////////////////////////////////////////////////////////////
//
// Real Time Signal Installer (POSIX)
//
/////////////////////////////////////////////////////////////////////////
sigfunc_rt *
sig_install(int signo, sigfunc_rt *func)
{
return sig_install_rt(signo, func);
}
int nan_x = 1, nan_y = 1, minusinf_x = 1, minusinf_y = 1, plusinf_x =
1, plusinf_y = 1;
/////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////
void
sig_handler(int signo)
{
signal(signo, sig_handler);
#ifdef DEBUG
cout << "Trapping signal number " << signo << endl;
#endif // DEBUG
switch(signo)
{
case SIGFPE:
{
jmp_buf *jbPtr = FPEHandler::instance().lastFPOLocation();
if(jbPtr)
longjmp(*jbPtr, 1);
else
{
cerr << "Cannot determine jump location ---- aborting \n\n
\n";
abort();
}
}
break;
default:
break;
}
}
/////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////
float
generate_plusInfinity(int x, int y) throw (runtime_error)
{
float retVal = 0;
jmp_buf *jbPtr = NULL;
if((jbPtr = FPEHandler::instance().openFPOLocation()) != NULL)
{
if(setjmp(*jbPtr) == 0)
{
retVal = (1)/(x-y);
FPEHandler::instance().closeFPOLocation(jbPtr);
}
else
throw runtime_error("Floating point error");
}
return retVal;
}
/////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////
float
generate_minusInfinity(int x, int y) throw (runtime_error)
{
float retVal = 0;
jmp_buf *jbPtr = NULL;
if((jbPtr = FPEHandler::instance().openFPOLocation()) != NULL)
{
if(setjmp(*jbPtr) == 0)
{
retVal = (-1)/(x-y) + generate_plusInfinity(plusinf_x,
plusinf_y);
FPEHandler::instance().closeFPOLocation(jbPtr);
}
else
throw runtime_error("Floating point error");
}
return retVal;
}
/////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////
void
generate_nan(int x, int y) throw (runtime_error)
{
float nan = 0;
x++; y+=2;
jmp_buf *jbPtr = NULL;
if((jbPtr = FPEHandler::instance().openFPOLocation()) != NULL)
{
if(setjmp(*jbPtr) == 0)
{
nan = generate_minusInfinity(minusinf_x, minusinf_y) + (x-2)/
(y-3);
FPEHandler::instance().closeFPOLocation(jbPtr);
}
else
throw runtime_error("Floating point error");
}
}
/////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////
main()
{
sig_install_trad(SIGFPE, sig_handler);
try
{
generate_nan(nan_x, nan_y);
}
catch (const exception& xcptn)
{
cerr << "Exception: " << xcptn.what() << " detected at " <<
__FILE__ << ", line " << __LINE__ << endl;
}
cout << "\n\n\n";
for(int i = -2; i < 3; i++)
{
try
{
generate_nan(i, i);
}
catch (const exception& xcptn)
{
cerr << "Exception: " << xcptn.what() << " detected at " <<
__FILE__ << ", line " << __LINE__ << endl;
}
cout << "In for loop with loop index " << i << "\n\n\n";
}
cout << "Goodbye\n";
}