Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com Message-Id: <199906222155.QAA22633@mercury.xraylith.wisc.edu> To: cygwin-developers AT sourceware DOT cygnus DOT com Subject: handling SIGFPE and resetting the FPU Date: Tue, 22 Jun 1999 16:55:53 -0500 From: Mumit Khan While trying to build libstdc++-v3, I ran into an odd problem with handling FPE in b20.1. If this is fixed in dev snapshots, please ignore this message. The problem is this: let's say you have a handler for FPE and it gets triggered by a an integer divide by zero; handler gets called and everybody's happy. Let's say you get another of these div_by_0 and now the handler never gets called and the process goes to sleep waiting for SIGFPE to be unblocked according to strace. I believe that the solution is to reset the FPU after handling (which includes the rather dangerous act of ignoring FPE) *each* FP exception in exceptions.cc:handle_exceptions(). That's what I do in Mingw runtime which runs the attached test code ok. Where's the patch you say? I have no patch is because I have no clue what it takes to reset the damn thing, but I assume it's a few-liner x86 assembly code for those in the know. Here's a test code (adapted from libstdc++-v3 src/gen-num-limits.cc): To test: $ c++ -g -o fpe-bug fpe-bug.cc $ ./fpe-bug If the bug is there, it'll get stuck in the test after getting through , , ... trap tests. is the one that gets the FPU all messed up, and gets stuck. === fpe-bug.cc: cut from here to end #include #include #include #include #include using namespace std; jmp_buf env; void signal_handler (int sig) { cerr << "In signal handler: " << sig << endl; longjmp(env, sig); } template bool trapping (const Operation& op) { if (setjmp(env) == 0) op(); else { cerr << "trapping: Returning from longjmp. " << endl; return true; } return false; } template struct division_by_zero { void operator() () const { volatile T zero = T(); volatile T one = T(1); volatile T infinity = one / zero; } }; template struct overflow { void operator() () const { T i = T (1); T j = T (); while (i > j) { j = i; i = i * 2 + 1; } } }; template struct underflow {}; template void traps() { cerr << __PRETTY_FUNCTION__ << ": Enter" << endl; #ifndef NO_SIGHANDLER signal (SIGFPE, signal_handler); #endif bool trap_flag = trapping (division_by_zero ()); cerr << "After trapping division_by_zero" << endl; #ifndef NO_SIGHANDLER signal (SIGFPE, signal_handler); #endif trap_flag = trap_flag && trapping (overflow ()); cerr << "After trapping overflow" << endl; cerr << __PRETTY_FUNCTION__ << ": Leave" << endl; } // type traits template struct type_trait { type_trait() { traps(); } }; int main () { cerr << "Testing ..." << endl; type_trait (); cerr << "Testing ..." << endl; type_trait (); #ifndef HIDE_BUG cerr << "Testing ..." << endl; type_trait (); cerr << "Testing ..." << endl; type_trait (); #endif /* HIDE_BUG */ return 0; }