diff --git a/src/Draw/TKQADraw/QABugs/QABugs_11.cxx b/src/Draw/TKQADraw/QABugs/QABugs_11.cxx index bf6423c832..ae656b4b2d 100644 --- a/src/Draw/TKQADraw/QABugs/QABugs_11.cxx +++ b/src/Draw/TKQADraw/QABugs/QABugs_11.cxx @@ -2352,76 +2352,6 @@ static int OCC6143(Draw_Interpretor& di, int argc, const char** argv) return 0; } -//! Auxiliary functor. -struct TestParallelFunctor -{ - TestParallelFunctor() - : myNbNotRaised(0), - myNbSigSegv(0), - myNbUnknown(0) - { - } - - int NbNotRaised() const { return myNbNotRaised; } - - int NbSigSegv() const { return myNbSigSegv; } - - int NbUnknown() const { return myNbUnknown; } - - void operator()(int theThreadId, int theTaskId) const - { - (void)theThreadId; - (void)theTaskId; - - // Test Access Violation - { - try - { - OCC_CATCH_SIGNALS - int* pint = nullptr; - *pint = 4; - ++myNbNotRaised; - } -#ifdef _WIN32 - catch (OSD_Exception_ACCESS_VIOLATION const&) -#else - catch (OSD_SIGSEGV const&) -#endif - { - ++myNbSigSegv; - } - catch (Standard_Failure const&) - { - ++myNbUnknown; - } - } - } - -private: - mutable std::atomic myNbNotRaised; - mutable std::atomic myNbSigSegv; - mutable std::atomic myNbUnknown; -}; - -static int OCC30775(Draw_Interpretor& theDI, int theNbArgs, const char**) -{ - if (theNbArgs != 1) - { - std::cout << "Syntax error: wrong number of arguments\n"; - return 1; - } - - occ::handle aPool = new OSD_ThreadPool(4); - OSD_ThreadPool::Launcher aLauncher(*aPool, 4); - TestParallelFunctor aFunctor; - aLauncher.Perform(0, 100, aFunctor); - theDI << "NbRaised: " << (aFunctor.NbSigSegv() + aFunctor.NbUnknown()) << "\n" - << "NbNotRaised: " << aFunctor.NbNotRaised() << "\n" - << "NbSigSeg: " << aFunctor.NbSigSegv() << "\n" - << "NbUnknown: " << aFunctor.NbUnknown() << "\n"; - return 0; -} - #if defined(_MSC_VER) && !defined(__clang__) #pragma optimize("", on) #endif @@ -5051,7 +4981,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands) theCommands.Add("OCC6046", "OCC6046 nb_of_vectors size", __FILE__, OCC6046, group); theCommands.Add("OCC5698", "OCC5698 wire", __FILE__, OCC5698, group); theCommands.Add("OCC6143", "OCC6143 catching signals", __FILE__, OCC6143, group); - theCommands.Add("OCC30775", "OCC30775 catching signals in threads", __FILE__, OCC30775, group); theCommands.Add("OCC30762", "OCC30762 printing backtrace", __FILE__, OCC30762, group); theCommands.Add("OCC7141", "OCC7141 [nCount] aPath", __FILE__, OCC7141, group); theCommands.Add("OCC7372", "OCC7372", __FILE__, OCC7372, group); diff --git a/src/FoundationClasses/TKernel/Standard/FILES.cmake b/src/FoundationClasses/TKernel/Standard/FILES.cmake index 8f1af8b7c6..d434afe9cd 100644 --- a/src/FoundationClasses/TKernel/Standard/FILES.cmake +++ b/src/FoundationClasses/TKernel/Standard/FILES.cmake @@ -37,13 +37,11 @@ set(OCCT_Standard_FILES Standard_GUID.cxx Standard_GUID.hxx Standard_Handle.hxx - Standard_HandlerStatus.hxx Standard_HashUtils.hxx Standard_HashUtils.lxx Standard_ImmutableObject.hxx Standard_Integer.hxx Standard_IStream.hxx - Standard_JmpBuf.hxx Standard_LicenseError.hxx Standard_LicenseNotFound.hxx Standard_Macro.hxx @@ -69,7 +67,6 @@ set(OCCT_Standard_FILES Standard_Overflow.hxx Standard_PByte.hxx Standard_PCharacter.hxx - Standard_PErrorHandler.hxx Standard_Persistent.cxx Standard_Persistent.hxx Standard_PExtCharacter.hxx diff --git a/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.cxx b/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.cxx index e45f7b7605..043ed25353 100644 --- a/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.cxx +++ b/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.cxx @@ -12,125 +12,51 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -//============================================================================ -//==== Title: Standard_ErrorHandler.cxx -//==== Role : class "Standard_ErrorHandler" implementation. -//============================================================================ #include + #include -#include - -#include -#include - -#ifndef _WIN32 - #include -#else - #include -#endif - -// =========================================================================== -// The class "Standard_ErrorHandler" variables -// =========================================================================== // During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try) // So if there is an abort request and if K_SETJMP is non zero, the abort // request will be ignored. If the abort request do a raise during a setjmp // or a longjmp, there will be a "terminating SEGV" impossible to handle. -//==== The top of the Errors Stack =========================================== -static Standard_ErrorHandler* Top = nullptr; +// The top of the Errors Stack -//================================================================================================= - -namespace -{ -// Using std::shared_mutex to allow concurrent read access from multiple threads. -// Most FindHandler calls (theUnlink=false) use shared_lock for concurrent searches. -// Only write operations (constructor, Unlink, FindHandler with theUnlink=true) use unique_lock. -// -// TODO: Long-term optimization - use thread_local storage to eliminate locking entirely. -// Since each thread only accesses its own error handlers (filtered by thread ID), -// this global list could be replaced with thread_local Top pointers. -// This would eliminate all mutex overhead for thousands of try blocks in multi-threaded code. -static std::shared_mutex THE_GLOBAL_MUTEX; - -static inline Standard_ThreadId GetThreadID() -{ -#ifndef _WIN32 - return (Standard_ThreadId)pthread_self(); -#else - return GetCurrentThreadId(); -#endif -} -} // namespace - -//============================================================================ -//==== Constructor : Create a ErrorHandler structure. And add it at the -//==== 'Top' of "ErrorHandler's stack". -//============================================================================ +static thread_local Standard_ErrorHandler* Top = nullptr; Standard_ErrorHandler::Standard_ErrorHandler() - : myStatus(Standard_HandlerVoid), - myCallbackPtr(nullptr) { - myThread = GetThreadID(); - memset(&myLabel, 0, sizeof(myLabel)); - - std::unique_lock aLock(THE_GLOBAL_MUTEX); myPrevious = Top; Top = this; } -//============================================================================ -//==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'. -//============================================================================ +//================================================================================================= void Standard_ErrorHandler::Destroy() { Unlink(); - if (myStatus == Standard_HandlerJumped) - { - // jumped, but not caught - Abort(myCaughtError); - } } //================================================================================================= void Standard_ErrorHandler::Unlink() { - // put a lock on the stack - std::unique_lock aLock(THE_GLOBAL_MUTEX); - - Standard_ErrorHandler* aPrevious = nullptr; - Standard_ErrorHandler* aCurrent = Top; - - // locate this handler in the stack - while (aCurrent != nullptr && this != aCurrent) + // Unlink handlers that were created after this one (shouldn't happen in normal usage) + while (Top != nullptr && Top != this) { - aPrevious = aCurrent; - aCurrent = aCurrent->myPrevious; + Top->Unlink(); } - if (aCurrent == nullptr) + if (Top == this) { - return; + Top = myPrevious; } - if (aPrevious == nullptr) - { - // a top exception taken - Top = aCurrent->myPrevious; - } - else - { - aPrevious->myPrevious = aCurrent->myPrevious; - } myPrevious = nullptr; // unlink and destroy all registered callbacks - void* aPtr = aCurrent->myCallbackPtr; + void* aPtr = myCallbackPtr; myCallbackPtr = nullptr; while (aPtr) { @@ -141,27 +67,20 @@ void Standard_ErrorHandler::Unlink() } } -//======================================================================= -// function : IsInTryBlock -// purpose : test if the code is currently running in -//======================================================================= +//================================================================================================= bool Standard_ErrorHandler::IsInTryBlock() { - Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, false); + Standard_ErrorHandler* anActive = FindHandler(); return anActive != nullptr; } -//============================================================================ -//==== Abort: make a longjmp to the saved Context. -//==== Abort if there is a non null 'Error' -//============================================================================ +//================================================================================================= void Standard_ErrorHandler::Abort(const occ::handle& theError) { - Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, true); + Standard_ErrorHandler* anActive = FindHandler(); - //==== Check if can do the "longjmp" ======================================= if (anActive == nullptr) { std::cerr << "*** Abort *** an exception was raised, but no catch was found." << std::endl; @@ -170,151 +89,34 @@ void Standard_ErrorHandler::Abort(const occ::handle& theError) exit(1); } - anActive->myStatus = Standard_HandlerJumped; + anActive->myCaughtError = theError; longjmp(anActive->myLabel, true); } -//============================================================================ -//==== Catches: If there is a 'Error', and it is in good type -//==== returns True and clean 'Error', else returns False. -//============================================================================ +//================================================================================================= -bool Standard_ErrorHandler::Catches(const occ::handle& AType) +void Standard_ErrorHandler::Raise() { - Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, false); - if (anActive == nullptr) - return false; - - if (anActive->myCaughtError.IsNull()) - return false; - - if (anActive->myCaughtError->IsKind(AType)) + if (myCaughtError.IsNull()) { - myStatus = Standard_HandlerProcessed; - return true; - } - else - { - return false; + std::cerr << "*** Abort *** an exception handler was called, but not exception object is set." + << std::endl; + exit(1); } + + myCaughtError->Reraise(); } -occ::handle Standard_ErrorHandler::LastCaughtError() +//================================================================================================= + +Standard_ErrorHandler* Standard_ErrorHandler::FindHandler() { - occ::handle aHandle; - Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, false); - if (anActive != nullptr) - aHandle = anActive->myCaughtError; - - return aHandle; -} - -occ::handle Standard_ErrorHandler::Error() const -{ - return myCaughtError; -} - -void Standard_ErrorHandler::Error(const occ::handle& theError) -{ - Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, false); - if (anActive == nullptr) - Abort(theError); - - anActive->myCaughtError = theError; -} - -Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus, - const bool theUnlink) -{ - // Use shared lock for read-only access (most common case), exclusive lock only when modifying - if (!theUnlink) - { - // Read-only path - use shared lock to allow concurrent searches from multiple threads - std::shared_lock aLock(THE_GLOBAL_MUTEX); - - // Find the current ErrorHandler according to thread - Standard_ErrorHandler* aCurrent = Top; - Standard_ThreadId aTreadId = GetThreadID(); - - // searching an exception with correct ID number - while (aCurrent != nullptr) - { - if (aTreadId == aCurrent->myThread && theStatus == aCurrent->myStatus) - { - // found one - return aCurrent; - } - aCurrent = aCurrent->myPrevious; - } - - return nullptr; - } - else - { - // Modifying path - use exclusive lock - std::unique_lock aLock(THE_GLOBAL_MUTEX); - - // Find the current ErrorHandler according to thread - Standard_ErrorHandler* aPrevious = nullptr; - Standard_ErrorHandler* aCurrent = Top; - Standard_ErrorHandler* anActive = nullptr; - bool aStop = false; - Standard_ThreadId aTreadId = GetThreadID(); - - // searching an exception with correct ID number - // which is not processed for the moment - while (!aStop) - { - while (aCurrent != nullptr && aTreadId != aCurrent->myThread) - { - aPrevious = aCurrent; - aCurrent = aCurrent->myPrevious; - } - - if (aCurrent != nullptr) - { - if (theStatus != aCurrent->myStatus) - { - // unlink current - if (aPrevious == nullptr) - { - // a top exception taken - Top = aCurrent->myPrevious; - } - else - { - aPrevious->myPrevious = aCurrent->myPrevious; - } - - // shift - aCurrent = aCurrent->myPrevious; - } - else - { - // found one - anActive = aCurrent; - aStop = true; - } - } - else - { - // Current is NULL, means that no handles - aStop = true; - } - } - - return anActive; - } + return Top; } #if defined(OCC_CONVERT_SIGNALS) -Standard_ErrorHandler::Callback::Callback() - : myHandler(nullptr), - myPrev(nullptr), - myNext(nullptr) -{ -} +Standard_ErrorHandler::Callback::Callback() {} Standard_ErrorHandler::Callback::~Callback() { @@ -327,7 +129,7 @@ void Standard_ErrorHandler::Callback::RegisterCallback() return; // already registered // find current active exception handler - Standard_ErrorHandler* aHandler = Standard_ErrorHandler::FindHandler(Standard_HandlerVoid, false); + Standard_ErrorHandler* aHandler = Standard_ErrorHandler::FindHandler(); // if found, add this callback object first to the list if (aHandler) diff --git a/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.hxx b/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.hxx index d41d872ec5..945e3065d3 100644 --- a/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.hxx +++ b/src/FoundationClasses/TKernel/Standard/Standard_ErrorHandler.hxx @@ -19,14 +19,9 @@ #include #include - -#include -#include -#include -#include #include -#include +#include //! @file //! Support of handling of C signals as C++-style exceptions, and implementation @@ -49,14 +44,13 @@ #if defined(OCC_CONVERT_SIGNALS) - // Exceptions are raied as usual, signal cause jumps in the nearest + // Exceptions are raised as usual, signal cause jumps in the nearest // OCC_CATCH_SIGNALS and then thrown as exceptions. #define OCC_CATCH_SIGNALS \ Standard_ErrorHandler _aHandler; \ if (setjmp(_aHandler.Label())) \ { \ - _aHandler.Catches(STANDARD_TYPE(Standard_Failure)); \ - _aHandler.Error()->Reraise(); \ + _aHandler.Raise(); \ } // Suppress GCC warning "variable ... might be clobbered by 'longjmp' or 'vfork'" @@ -75,12 +69,11 @@ class Standard_Failure; //! Class implementing mechanics of conversion of signals to exceptions. //! -//! Each instance of it stores data for jump placement, thread id, +//! Each instance of it stores data for jump placement, //! and callbacks to be called during jump (for proper resource release). //! //! The active handlers are stored in the global stack, which is used //! to find appropriate handler when signal is raised. - class Standard_ErrorHandler { public: @@ -96,39 +89,30 @@ public: //! Destructor ~Standard_ErrorHandler() { Destroy(); } - //! Removes handler from the handlers list - Standard_EXPORT void Unlink(); - - //! Returns "True" if the caught exception has the same type - //! or inherits from "aType" - Standard_EXPORT bool Catches(const occ::handle& aType); + //! Throws C++ exception if exception object set, + //! otherwise prints error and terminates program. + Standard_EXPORT void Raise(); //! Returns label for jump - Standard_JmpBuf& Label() { return myLabel; } + jmp_buf& Label() { return myLabel; } //! Returns the current Error. - Standard_EXPORT occ::handle Error() const; - - //! Returns the caught exception. - Standard_EXPORT static occ::handle LastCaughtError(); + const occ::handle& Error() const { return myCaughtError; } //! Test if the code is currently running in a try block Standard_EXPORT static bool IsInTryBlock(); private: - //! A exception is raised but it is not yet caught. - //! So Abort the current function and transmit the exception - //! to "calling routines". - //! Warning: If no catch is prepared for this exception, it displays the - //! exception name and calls "exit(1)". - Standard_EXPORT static void Abort(const occ::handle& theError); + //! Removes handler from the list. + void Unlink(); - //! Set the Error which will be transmitted to "calling routines". - Standard_EXPORT static void Error(const occ::handle& aError); + //! Finds nearest error handler in the stack and sets its exception object to @p theError + //! and long jump which then throw normal C++ exception. + //! If handler not found, prints error and exit program with error code @c 1. + static void Abort(const occ::handle& theError); //! Returns the current handler (closest in the stack in the current execution thread) - Standard_EXPORT static Standard_PErrorHandler FindHandler(const Standard_HandlerStatus theStatus, - const bool theUnlink); + static Standard_ErrorHandler* FindHandler(); public: //! Defines a base class for callback objects that can be registered @@ -186,20 +170,18 @@ public: Callback(); private: - void* myHandler; - void* myPrev; - void* myNext; + void* myHandler = nullptr; + void* myPrev = nullptr; + void* myNext = nullptr; friend class Standard_ErrorHandler; }; private: - Standard_PErrorHandler myPrevious; + Standard_ErrorHandler* myPrevious = nullptr; occ::handle myCaughtError; - Standard_JmpBuf myLabel; - Standard_HandlerStatus myStatus; - Standard_ThreadId myThread; - Callback* myCallbackPtr; + jmp_buf myLabel = {}; + Callback* myCallbackPtr = nullptr; friend class Standard_Failure; }; @@ -207,18 +189,9 @@ private: // If OCC_CONVERT_SIGNALS is not defined, // provide empty inline implementation #if !defined(OCC_CONVERT_SIGNALS) -inline Standard_ErrorHandler::Callback::Callback() - : myHandler(0), - myPrev(0), - myNext(0) -{ -} +inline Standard_ErrorHandler::Callback::Callback() {} -inline Standard_ErrorHandler::Callback::~Callback() -{ - (void)myHandler; - (void)myPrev; -} +inline Standard_ErrorHandler::Callback::~Callback() {} inline void Standard_ErrorHandler::Callback::RegisterCallback() {} diff --git a/src/FoundationClasses/TKernel/Standard/Standard_Failure.cxx b/src/FoundationClasses/TKernel/Standard/Standard_Failure.cxx index 764c963ea0..e1b2dd48d8 100644 --- a/src/FoundationClasses/TKernel/Standard/Standard_Failure.cxx +++ b/src/FoundationClasses/TKernel/Standard/Standard_Failure.cxx @@ -233,7 +233,6 @@ void Standard_Failure::Reraise() void Standard_Failure::Jump() { #if defined(OCC_CONVERT_SIGNALS) - Standard_ErrorHandler::Error(this); Standard_ErrorHandler::Abort(this); #else Throw(); diff --git a/src/FoundationClasses/TKernel/Standard/Standard_HandlerStatus.hxx b/src/FoundationClasses/TKernel/Standard/Standard_HandlerStatus.hxx deleted file mode 100644 index c1c01e0190..0000000000 --- a/src/FoundationClasses/TKernel/Standard/Standard_HandlerStatus.hxx +++ /dev/null @@ -1,27 +0,0 @@ -// Created on: 1991-09-05 -// Created by: J.P. TIRAUlt -// Copyright (c) 1991-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -#ifndef _Standard_HandlerStatus_HeaderFile -#define _Standard_HandlerStatus_HeaderFile - -enum Standard_HandlerStatus -{ - Standard_HandlerVoid, - Standard_HandlerJumped, - Standard_HandlerProcessed -}; - -#endif // _Standard_HandlerStatus_HeaderFile diff --git a/src/FoundationClasses/TKernel/Standard/Standard_JmpBuf.hxx b/src/FoundationClasses/TKernel/Standard/Standard_JmpBuf.hxx deleted file mode 100644 index 44a9406c29..0000000000 --- a/src/FoundationClasses/TKernel/Standard/Standard_JmpBuf.hxx +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -#ifndef _Standard_JmpBuf_HeaderFile -#define _Standard_JmpBuf_HeaderFile - -#include - -typedef -#ifdef SOLARIS - sigjmp_buf -#elif defined(IRIX) - sigjmp_buf -#else - jmp_buf -#endif - Standard_JmpBuf; - -#endif diff --git a/src/FoundationClasses/TKernel/Standard/Standard_PErrorHandler.hxx b/src/FoundationClasses/TKernel/Standard/Standard_PErrorHandler.hxx deleted file mode 100644 index dbf24fc751..0000000000 --- a/src/FoundationClasses/TKernel/Standard/Standard_PErrorHandler.hxx +++ /dev/null @@ -1,23 +0,0 @@ -// Created on: 1991-09-05 -// Created by: J.P. TIRAUlt -// Copyright (c) 1991-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -#ifndef _Standard_PErrorHandler_HeaderFile -#define _Standard_PErrorHandler_HeaderFile - -class Standard_ErrorHandler; -typedef Standard_ErrorHandler* Standard_PErrorHandler; - -#endif // _Standard_PErrorHandler_HeaderFile diff --git a/tests/bugs/fclasses/bug30775 b/tests/bugs/fclasses/bug30775 deleted file mode 100644 index a5ce1e97c6..0000000000 --- a/tests/bugs/fclasses/bug30775 +++ /dev/null @@ -1,24 +0,0 @@ -puts "================" -puts "0030775: OSD::SetSignal() within OSD_ThreadPool should not override global handlers" -puts "================" -puts "" - -pload QAcommands - -dsetsignal set - -set IsDone [catch {set aResult [OCC30775]} result] - -if { ${IsDone} != 0 } { - puts "result = ${result}" - puts "Error: command raised exception" -} else { - if { [string first "NbRaised: 100" $aResult] != -1 } { - puts "OK test case" - } else { - puts "Error: expected to have 100 raised exceptions" - } -} - -# restore defaults -dsetsignal \ No newline at end of file