1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 //============================================================================
16 //==== Titre: Standard_ErrorHandler.cxx
17 //==== Role : class "Standard_ErrorHandler" implementation.
18 //============================================================================
19 #include <Standard_ErrorHandler.hxx>
20 #include <Standard_Failure.hxx>
21 #include <Standard_ErrorHandlerCallback.hxx>
22 #include <Standard_Mutex.hxx>
23 #include <Standard.hxx>
31 // ===========================================================================
32 // The class "Standard_ErrorHandler" variables
33 // ===========================================================================
35 // During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
36 // So if there is an abort request and if K_SETJMP is non zero, the abort
37 // request will be ignored. If the abort request do a raise during a setjmp
38 // or a longjmp, there will be a "terminating SEGV" impossible to handle.
40 //==== The top of the Errors Stack ===========================================
41 static Standard_ErrorHandler* Top = 0;
43 // A mutex to protect from concurrent access to Top
44 // Note that we should NOT use Sentry while in this class, as Sentry
45 // would register mutex as callback in the current exception handler
46 static Standard_Mutex theMutex;
48 static inline Standard_ThreadId GetThreadID()
51 return pthread_self();
53 return GetCurrentThreadId();
57 //============================================================================
58 //==== Constructor : Create a ErrorHandler structure. And add it at the
59 //==== 'Top' of "ErrorHandler's stack".
60 //============================================================================
62 Standard_ErrorHandler::Standard_ErrorHandler () :
63 myStatus(Standard_HandlerVoid), myCallbackPtr(0)
65 myThread = GetThreadID();
74 //============================================================================
75 //==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
76 //============================================================================
78 void Standard_ErrorHandler::Destroy()
81 if (myStatus == Standard_HandlerJumped)
83 // jumped, but not caught
84 Abort (myCaughtError);
89 //=======================================================================
92 //=======================================================================
94 void Standard_ErrorHandler::Unlink()
96 // put a lock on the stack
99 Standard_ErrorHandler* aPrevious = 0;
100 Standard_ErrorHandler* aCurrent = Top;
102 // locate this handler in the stack
103 while(aCurrent!=0 && this!=aCurrent) {
104 aPrevious = aCurrent;
105 aCurrent = aCurrent->myPrevious;
114 // a top exception taken
115 Top = aCurrent->myPrevious;
118 aPrevious->myPrevious=aCurrent->myPrevious;
123 // unlink and destroy all registered callbacks
124 Standard_Address aPtr = aCurrent->myCallbackPtr;
127 Standard_ErrorHandlerCallback* aCallback = (Standard_ErrorHandlerCallback*)aPtr;
128 aPtr = aCallback->myNext;
129 // Call destructor explicitly, as we know that it will not be called automatically
130 aCallback->DestroyCallback();
134 //=======================================================================
135 //function : IsInTryBlock
136 //purpose : test if the code is currently running in
137 //=======================================================================
139 Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
141 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
142 return anActive != NULL && anActive->myLabel != NULL;
146 //============================================================================
147 //==== Abort: make a longjmp to the saved Context.
148 //==== Abort if there is a non null 'Error'
149 //============================================================================
151 void Standard_ErrorHandler::Abort (const Handle(Standard_Failure)& theError)
153 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);
155 //==== Check if can do the "longjmp" =======================================
156 if(anActive == NULL || anActive->myLabel == NULL) {
157 cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
158 if (!theError.IsNull())
159 cerr << "\t... The exception is:" << theError->GetMessageString() << endl;
163 anActive->myStatus = Standard_HandlerJumped;
164 longjmp(anActive->myLabel, Standard_True);
168 //============================================================================
169 //==== Catches: If there is a 'Error', and it is in good type
170 //==== returns True and clean 'Error', else returns False.
171 //============================================================================
173 Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
175 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
177 return Standard_False;
179 if(anActive->myCaughtError.IsNull())
180 return Standard_False;
182 if(anActive->myCaughtError->IsKind(AType)){
183 myStatus=Standard_HandlerProcessed;
184 return Standard_True;
186 return Standard_False;
190 Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
192 Handle(Standard_Failure) aHandle;
193 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
195 aHandle = anActive->myCaughtError;
200 Handle(Standard_Failure) Standard_ErrorHandler::Error() const
202 return myCaughtError;
206 void Standard_ErrorHandler::Error (const Handle(Standard_Failure)& theError)
208 Standard_ErrorHandler* anActive = FindHandler (Standard_HandlerVoid, Standard_False);
209 if (anActive == NULL)
212 anActive->myCaughtError = theError;
216 Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
217 const Standard_Boolean theUnlink)
222 // Find the current ErrorHandler Accordin tread
223 Standard_ErrorHandler* aPrevious = 0;
224 Standard_ErrorHandler* aCurrent = Top;
225 Standard_ErrorHandler* anActive = 0;
226 Standard_Boolean aStop = Standard_False;
227 Standard_ThreadId aTreadId = GetThreadID();
229 // searching an exception with correct ID number
230 // which is not processed for the moment
232 while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
233 aPrevious = aCurrent;
234 aCurrent = aCurrent->myPrevious;
238 if(theStatus!=aCurrent->myStatus) {
243 // a top exception taken
244 Top = aCurrent->myPrevious;
247 aPrevious->myPrevious=aCurrent->myPrevious;
252 aCurrent = aCurrent->myPrevious;
257 aStop = Standard_True;
261 //Current is NULL, means that no handlesr
262 aStop = Standard_True;