1 //============================================================================
2 //==== Titre: Standard_ErrorHandler.cxx
3 //==== Role : class "Standard_ErrorHandler" implementation.
4 //============================================================================
5 #include <Standard_ErrorHandler.hxx>
6 #include <Standard_Failure.hxx>
7 #include <Standard_ErrorHandlerCallback.hxx>
8 #include <Standard_Mutex.hxx>
9 #include <Standard.hxx>
17 // ===========================================================================
18 // The class "Standard_ErrorHandler" variables
19 // ===========================================================================
21 // During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
22 // So if there is an abort request and if K_SETJMP is non zero, the abort
23 // request will be ignored. If the abort request do a raise during a setjmp
24 // or a longjmp, there will be a "terminating SEGV" impossible to handle.
26 //==== The top of the Errors Stack ===========================================
27 static Standard_ErrorHandler* Top = 0;
29 // A mutex to protect from concurrent access to Top
30 // Note that we should NOT use Sentry while in this class, as Sentry
31 // would register mutex as callback in the current exception handler
32 static Standard_Mutex theMutex;
34 static inline Standard_ThreadId GetThreadID()
37 return pthread_self();
39 return GetCurrentThreadId();
43 //============================================================================
44 //==== Constructor : Create a ErrorHandler structure. And add it at the
45 //==== 'Top' of "ErrorHandler's stack".
46 //============================================================================
48 Standard_ErrorHandler::Standard_ErrorHandler () :
49 myStatus(Standard_HandlerVoid), myCallbackPtr(0)
51 myThread = GetThreadID();
53 if (Standard::IsReentrant())
57 if (Standard::IsReentrant())
62 //============================================================================
63 //==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
64 //============================================================================
66 void Standard_ErrorHandler::Destroy()
69 if (myStatus == Standard_HandlerJumped)
71 // jumped, but not caught
72 Abort (myCaughtError);
77 //=======================================================================
80 //=======================================================================
82 void Standard_ErrorHandler::Unlink()
84 // put a lock on the stack
85 if (Standard::IsReentrant())
88 Standard_ErrorHandler* aPrevious = 0;
89 Standard_ErrorHandler* aCurrent = Top;
91 // locate this handler in the stack
92 while(aCurrent!=0 && this!=aCurrent) {
94 aCurrent = aCurrent->myPrevious;
98 if (Standard::IsReentrant())
104 // a top exception taken
105 Top = aCurrent->myPrevious;
108 aPrevious->myPrevious=aCurrent->myPrevious;
111 if (Standard::IsReentrant())
114 // unlink and destroy all registered callbacks
115 Standard_Address aPtr = aCurrent->myCallbackPtr;
118 Standard_ErrorHandlerCallback* aCallback = (Standard_ErrorHandlerCallback*)aPtr;
119 aPtr = aCallback->myNext;
120 // Call destructor explicitly, as we know that it will not be called automatically
121 aCallback->DestroyCallback();
125 //=======================================================================
126 //function : IsInTryBlock
127 //purpose : test if the code is currently running in
128 //=======================================================================
130 Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
132 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
133 return anActive != NULL && anActive->myLabel != NULL;
137 //============================================================================
138 //==== Abort: make a longjmp to the saved Context.
139 //==== Abort if there is a non null 'Error'
140 //============================================================================
142 void Standard_ErrorHandler::Abort (const Handle(Standard_Failure)& theError)
144 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);
146 //==== Check if can do the "longjmp" =======================================
147 if(anActive == NULL || anActive->myLabel == NULL) {
148 cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
149 if (!theError.IsNull())
150 cerr << "\t... The exception is:" << theError->GetMessageString() << endl;
154 anActive->myStatus = Standard_HandlerJumped;
155 longjmp(anActive->myLabel, Standard_True);
159 //============================================================================
160 //==== Catches: If there is a 'Error', and it is in good type
161 //==== returns True and clean 'Error', else returns False.
162 //============================================================================
164 Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
166 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
168 return Standard_False;
170 if(anActive->myCaughtError.IsNull())
171 return Standard_False;
173 if(anActive->myCaughtError->IsKind(AType)){
174 myStatus=Standard_HandlerProcessed;
175 return Standard_True;
177 return Standard_False;
181 Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
183 Handle(Standard_Failure) aHandle;
184 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
186 aHandle = anActive->myCaughtError;
191 Handle(Standard_Failure) Standard_ErrorHandler::Error() const
193 return myCaughtError;
197 void Standard_ErrorHandler::Error (const Handle(Standard_Failure)& theError)
199 Standard_ErrorHandler* anActive = FindHandler (Standard_HandlerVoid, Standard_False);
200 if (anActive == NULL)
203 anActive->myCaughtError = theError;
207 Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
208 const Standard_Boolean theUnlink)
211 if (Standard::IsReentrant())
214 // Find the current ErrorHandler Accordin tread
215 Standard_ErrorHandler* aPrevious = 0;
216 Standard_ErrorHandler* aCurrent = Top;
217 Standard_ErrorHandler* anActive = 0;
218 Standard_Boolean aStop = Standard_False;
219 Standard_ThreadId aTreadId = GetThreadID();
221 // searching an exception with correct ID number
222 // which is not processed for the moment
224 while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
225 aPrevious = aCurrent;
226 aCurrent = aCurrent->myPrevious;
230 if(theStatus!=aCurrent->myStatus) {
235 // a top exception taken
236 Top = aCurrent->myPrevious;
239 aPrevious->myPrevious=aCurrent->myPrevious;
244 aCurrent = aCurrent->myPrevious;
249 aStop = Standard_True;
253 //Current is NULL, means that no handlesr
254 aStop = Standard_True;
257 if (Standard::IsReentrant())