X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=blobdiff_plain;f=src%2FOSD%2FOSD_signal.cxx;h=654523afd9a655335139a88fe2a77dbbf80f3f95;hb=44b80414d3ec94cf5d7438a8a51bcb72ac8379b1;hpb=b1492cb30fcac293dcedabecb914a8a9db0fe536 diff --git a/src/OSD/OSD_signal.cxx b/src/OSD/OSD_signal.cxx index 1b712deccf..654523afd9 100644 --- a/src/OSD/OSD_signal.cxx +++ b/src/OSD/OSD_signal.cxx @@ -16,16 +16,17 @@ #include #include #include +#include -static Standard_THREADLOCAL Standard_Boolean fFltExceptions = Standard_False; +static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs; //======================================================================= -//function : ToCatchFloatingSignals +//function : SignalMode //purpose : //======================================================================= -Standard_Boolean OSD::ToCatchFloatingSignals() +OSD_SignalMode OSD::SignalMode() { - return fFltExceptions; + return OSD_WasSetSignal; } #ifdef _WIN32 @@ -90,7 +91,6 @@ static Standard_Boolean fDbgLoaded; static LONG _osd_debug ( void ); #endif -//# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW ) # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW ) #ifdef OCC_CONVERT_SIGNALS @@ -236,15 +236,16 @@ static LONG CallHandler (DWORD dwExceptionCode, } // end switch + // reset FPE state (before message box, otherwise it may fail to show up) + if ( flterr ) { + OSD::SetFloatingSignal (Standard_True); + } + +#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__) // provide message to the user with possibility to stop size_t idx; StringCchLengthW (buffer, _countof(buffer),&idx); if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) { - // reset FP operations before message box, otherwise it may fail to show up - _fpreset(); - _clearfp(); - -#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__) MessageBeep ( MB_ICONHAND ); int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP); if (aChoice == IDRETRY) @@ -253,17 +254,8 @@ static LONG CallHandler (DWORD dwExceptionCode, DebugBreak(); } else if (aChoice == IDABORT) exit(0xFFFF); -#endif - } - - // reset FPE state - if ( flterr ) { - if ( !fFltExceptions ) return EXCEPTION_EXECUTE_HANDLER; - _fpreset () ; - _clearfp() ; - _controlfp ( 0, _OSD_FPX ) ; // JR add : -// std::cout << "OSD::WntHandler _controlfp( 0, _OSD_FPX ) " << std::hex << _controlfp(0,0) << std::dec << std::endl ; } +#endif char aBufferA[2048]; WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBufferA, sizeof(aBufferA), NULL, NULL); @@ -367,13 +359,60 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP) lpXP->ExceptionRecord->ExceptionInformation[0]); } +//======================================================================= +//function : SetFloatingSignal +//purpose : +//======================================================================= +void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal) +{ + _fpreset(); + _clearfp(); + + // Note: zero bit means exception will be raised + _controlfp (theFloatingSignal ? 0 : _OSD_FPX, _OSD_FPX); +} + +//======================================================================= +//function : ToCatchFloatingSignals +//purpose : +//======================================================================= +Standard_Boolean OSD::ToCatchFloatingSignals() +{ + // return true if at least one of bits within _OSD_FPX + // is unset, which means relevant FPE will raise exception + int aControlWord = _controlfp (0, 0); + return (_OSD_FPX & ~aControlWord) != 0; +} + +//======================================================================= +//function : SetThreadLocalSignal +//purpose : +//======================================================================= +void OSD::SetThreadLocalSignal (OSD_SignalMode theSignalMode, + Standard_Boolean theFloatingSignal) +{ +#ifdef _MSC_VER + _se_translator_function aPreviousFunc = NULL; + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) + aPreviousFunc = _set_se_translator(TranslateSE); + if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL)) + _set_se_translator(aPreviousFunc); +#else + (void)theSignalMode; +#endif + SetFloatingSignal (theFloatingSignal); +} + //======================================================================= //function : SetSignal //purpose : //======================================================================= -void OSD::SetSignal (const Standard_Boolean theFloatingSignal) +void OSD::SetSignal (OSD_SignalMode theSignalMode, + Standard_Boolean theFloatingSignal) { Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling + OSD_WasSetSignal = theSignalMode; + #if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2) OSD_Environment env ("CSF_DEBUG_MODE"); TCollection_AsciiString val = env.Value(); @@ -391,37 +430,53 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal) // when user's code is compiled with /EHs // Replaces the existing top-level exception filter for all existing and all future threads // in the calling process - ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler); + { + LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFunc = NULL; + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) + { + aPreviousFunc = ::SetUnhandledExceptionFilter(WntHandler); + } + if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL)) + { + ::SetUnhandledExceptionFilter(aPreviousFunc); + } + } #endif // NTDDI_WIN10_TH2 - // Signal handlers will only be used when the method ::raise() will be used - // Handlers must be set for every thread - if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR) - std::cout << "signal(OSD::SetSignal) error\n"; - if (signal (SIGFPE, (void(*)(int))SIGWntHandler) == SIG_ERR) - std::cout << "signal(OSD::SetSignal) error\n"; - if (signal (SIGILL, (void(*)(int))SIGWntHandler) == SIG_ERR) - std::cout << "signal(OSD::SetSignal) error\n"; + // Signal handlers will only be used when function ::raise() is called + const int NBSIG = 3; + const int aSignalTypes[NBSIG] = { SIGSEGV, SIGILL, SIGFPE }; + for (int i = 0; i < NBSIG; ++i) + { + typedef void (*SignalFuncType)(int); // same as _crt_signal_t available since vc14 + SignalFuncType aPreviousFunc = SIG_DFL; + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) + { + aPreviousFunc = signal(aSignalTypes[i], (SignalFuncType)SIGWntHandler); + } + if (theSignalMode == OSD_SignalMode_Unset || + (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != SIG_DFL && aPreviousFunc != SIG_ERR)) + { + aPreviousFunc = signal(aSignalTypes[i], aPreviousFunc); + } + Standard_ASSERT(aPreviousFunc != SIG_ERR, "signal() failed", std::cout << "OSD::SetSignal(): signal() returns SIG_ERR"); + } // Set Ctrl-C and Ctrl-Break handler fCtrlBrk = Standard_False; #ifndef OCCT_UWP - SetConsoleCtrlHandler (&_osd_ctrl_break_handler, TRUE); -#endif -#ifdef _MSC_VER -// _se_translator_function pOldSeFunc = - _set_se_translator (TranslateSE); -#endif - - fFltExceptions = theFloatingSignal; - if (theFloatingSignal) + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) { - _controlfp (0, _OSD_FPX); // JR add : + SetConsoleCtrlHandler(&_osd_ctrl_break_handler, true); } - else { - _controlfp (_OSD_FPX, _OSD_FPX); // JR add : + else if (theSignalMode == OSD_SignalMode_Unset) + { + SetConsoleCtrlHandler(&_osd_ctrl_break_handler, false); } -} // end OSD :: SetSignal +#endif + + SetThreadLocalSignal (theSignalMode, theFloatingSignal); +} //============================================================================ //==== ControlBreak @@ -636,18 +691,12 @@ static Standard_Boolean fCtrlBrk; typedef void (ACT_SIGIO_HANDLER)(void) ; ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ; -#ifdef DECOSF1 -typedef void (* SIG_PFV) (int); -#endif - #ifdef __GNUC__ # include # include #else # ifdef SA_SIGINFO -# ifndef _AIX # include -# endif # endif #endif typedef void (* SIG_PFV) (int); @@ -658,6 +707,8 @@ typedef void (* SIG_PFV) (int); #include #endif +# define _OSD_FPX (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW) + //============================================================================ //==== Handler //==== Catche the differents signals: @@ -696,11 +747,7 @@ static void Handler (const int theSignal) // std::cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " << std::endl ; if ( ADR_ACT_SIGIO_HANDLER != NULL ) (*ADR_ACT_SIGIO_HANDLER)() ; -#ifdef __linux__ - if (fFltExceptions) - feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); - //feenableexcept (FE_INVALID | FE_DIVBYZERO); -#endif + sigset_t set; sigemptyset(&set); switch (theSignal) { @@ -746,10 +793,8 @@ static void Handler (const int theSignal) case SIGFPE: sigaddset(&set, SIGFPE); sigprocmask(SIG_UNBLOCK, &set, NULL) ; -#ifdef DECOSF1 - // Pour DEC/OSF1 SIGFPE = Division par zero. - Standard_DivideByZero::NewInstance('')->Jump; - break; +#ifdef __linux__ + OSD::SetFloatingSignal (Standard_True); #endif #if (!defined (__sun)) && (!defined(SOLARIS)) Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump(); @@ -788,12 +833,6 @@ static void Handler (const int theSignal) } #endif break; -#if defined (__sgi) || defined(IRIX) - case SIGTRAP: - sigaddset(&set, SIGTRAP); - sigprocmask(SIG_UNBLOCK, &set, NULL) ; - Standard_DivideByZero::NewInstance("SIGTRAP IntegerDivideByZero")->Jump(); break; -#endif default: #ifdef OCCT_DEBUG std::cout << "Unexpected signal " << theSignal << std::endl ; @@ -814,11 +853,6 @@ static void SegvHandler(const int theSignal, (void)theSignal; // silence GCC warnings (void)theContext; -#ifdef __linux__ - if (fFltExceptions) - feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); - //feenableexcept (FE_INVALID | FE_DIVBYZERO); -#endif // std::cout << "OSD::SegvHandler activated(SA_SIGINFO)" << std::endl ; if ( ip != NULL ) { sigset_t set; @@ -874,160 +908,127 @@ static void SegvHandler(const int theSignal, #endif -//============================================================================ -//==== SetSignal -//==== Set the differents signals: -//============================================================================ - -void OSD::SetSignal(const Standard_Boolean aFloatingSignal) +//======================================================================= +//function : SetFloatingSignal +//purpose : +//======================================================================= +void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal) { - struct sigaction act, oact; - int stat = 0; - - if( aFloatingSignal ) { - //==== Enable the floating point exceptions =============== -#if defined (__sun) || defined (SOLARIS) - sigfpe_handler_type PHandler = (sigfpe_handler_type) Handler ; - stat = ieee_handler("set", "invalid", PHandler); - stat = ieee_handler("set", "division", PHandler) || stat; - stat = ieee_handler("set", "overflow", PHandler) || stat; - - //stat = ieee_handler("set", "underflow", PHandler) || stat; - //stat = ieee_handler("set", "inexact", PHandler) || stat; - - if (stat) { -#ifdef OCCT_DEBUG - std::cerr << "ieee_handler does not work !!! KO " << std::endl; -#endif - } -#elif defined (__linux__) - feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); - fFltExceptions = Standard_True; -#endif +#if defined (__linux__) + feclearexcept (FE_ALL_EXCEPT); + if (theFloatingSignal) + { + feenableexcept (_OSD_FPX); } else { -#if defined (__linux__) - fedisableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); - fFltExceptions = Standard_False; -#endif + fedisableexcept (_OSD_FPX); } - -#if defined (sgi) || defined (IRIX ) - char *TRAP_FPE = getenv("TRAP_FPE") ; - if ( TRAP_FPE == NULL ) { -#ifdef OCCT_DEBUG - std::cout << "On SGI you must set TRAP_FPE environment variable : " << std::endl ; - std::cout << "set env(TRAP_FPE) \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\" or" << std::endl ; - std::cout << "setenv TRAP_FPE \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\"" << std::endl ; -#endif - } -#endif - - //==== Save the old Signal Handler, and set the new one =================== - - sigemptyset(&act.sa_mask) ; - -#ifdef SA_RESTART - act.sa_flags = SA_RESTART ; -#else - act.sa_flags = 0 ; -#endif -#ifdef SA_SIGINFO - act.sa_flags = act.sa_flags | SA_SIGINFO ; - act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ Handler; -#else - act.sa_handler = /*(SIG_PFV)*/ Handler; -#endif - - //==== Always detected the signal "SIGFPE" ================================= - stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception - if (stat) { +#elif defined (__sun) || defined (SOLARIS) + int aSunStat = 0; + sigfpe_handler_type anFpeHandler = (theFloatingSignal ? (sigfpe_handler_type)Handler : NULL); + aSunStat = ieee_handler ("set", "invalid", anFpeHandler); + aSunStat = ieee_handler ("set", "division", anFpeHandler) || aSunStat; + aSunStat = ieee_handler ("set", "overflow", anFpeHandler) || aSunStat; + if (aSunStat) + { #ifdef OCCT_DEBUG - std::cerr << "sigaction does not work !!! KO " << std::endl; + std::cerr << "ieee_handler does not work !!! KO\n"; #endif - perror("sigaction "); } - - //==== Detected the only the "free" signals ================================ - sigaction(SIGHUP,&act,&oact); // ...... hangup - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGHUP,&oact,&oact); -#endif - - sigaction(SIGINT,&act,&oact); // ...... interrupt - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGINT,&oact,&oact); -#endif - - sigaction(SIGQUIT,&act,&oact); // ...... quit - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGQUIT,&oact,&oact); +#else + (void)theFloatingSignal; #endif +} - sigaction(SIGILL,&act,&oact); // ...... illegal instruction - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGILL,&oact,&oact); +//======================================================================= +//function : ToCatchFloatingSignals +//purpose : +//======================================================================= +Standard_Boolean OSD::ToCatchFloatingSignals() +{ +#if defined (__linux__) + return (fegetexcept() & _OSD_FPX) != 0; +#else + return Standard_False; #endif +} - sigaction(SIGBUS,&act,&oact); // ...... bus error - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGBUS,&oact,&oact); -#endif +//======================================================================= +//function : SetThreadLocalSignal +//purpose : +//======================================================================= +void OSD::SetThreadLocalSignal (OSD_SignalMode /*theSignalMode*/, + Standard_Boolean theFloatingSignal) +{ + SetFloatingSignal (theFloatingSignal); +} -#if !defined(__linux__) - sigaction(SIGSYS,&act,&oact); // ...... bad argument to system call +//============================================================================ +//==== SetSignal +//==== Set the differents signals: +//============================================================================ -# ifdef OBJS - if(oact.sa_handler) - sigaction(SIGSYS,&oact,&oact); -# endif -#endif +void OSD::SetSignal (OSD_SignalMode theSignalMode, + Standard_Boolean theFloatingSignal) +{ + SetFloatingSignal (theFloatingSignal); -#if defined (__sgi) || defined(IRIX) - sigaction(SIGTRAP,&act,&oact); // Integer Divide By Zero (IRIX) + OSD_WasSetSignal = theSignalMode; + if (theSignalMode == OSD_SignalMode_AsIs) + { + return; // nothing to be done with signal handlers + } -# ifdef OBJS - if(oact.sa_handler) - sigaction(SIGTRAP,&oact,&oact); -# endif + // Prepare signal descriptors + struct sigaction anActSet, anActDfl, anActOld; + sigemptyset(&anActSet.sa_mask); + sigemptyset(&anActDfl.sa_mask); + sigemptyset(&anActOld.sa_mask); +#ifdef SA_RESTART + anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART; +#else + anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0; #endif - #ifdef SA_SIGINFO - act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler; + anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO; + anActSet.sa_sigaction = Handler; #else - act.sa_handler = /*(SIG_PFV)*/ SegvHandler; + anActSet.sa_handler = Handler; #endif + anActDfl.sa_handler = SIG_DFL; - if ( sigaction( SIGSEGV , &act , &oact ) ) // ...... segmentation violation - perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ; - -#ifdef OBJS - if(oact.sa_handler) - sigaction(SIGSEGV,&oact,&oact); -#endif -#if defined(__osf__) || defined(DECOSF1) - struct sigaction action, prev_action; - action.sa_handler = SIG_IGN; - action.sa_mask = 0; - action.sa_flags = 0; - - if (sigaction (SIGFPE, &action, &prev_action) == -1) { - perror ("sigaction"); - exit (1); - } + // Set signal handlers; NB: SIGSEGV must be the last one! + const int NBSIG = 8; + const int aSignalTypes[NBSIG] = { SIGFPE, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSYS, SIGSEGV }; + for (int i = 0; i < NBSIG; ++i) + { + // SIGSEGV has special handler + if (aSignalTypes[i] == SIGSEGV) + { +#ifdef SA_SIGINFO + anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler; +#else + anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler; #endif + } + // set handler according to specified mode and current handler + int retcode = -1; + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) + { + retcode = sigaction (aSignalTypes[i], &anActSet, &anActOld); + } + else if (theSignalMode == OSD_SignalMode_Unset) + { + retcode = sigaction (aSignalTypes[i], &anActDfl, &anActOld); + } + if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0 && anActOld.sa_handler != SIG_DFL) + { + retcode = sigaction (aSignalTypes[i], &anActOld, &anActOld); + } + Standard_ASSERT(retcode == 0, "sigaction() failed", std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalTypes[i] << std::endl); + } } //============================================================================