0023988: Force use of reentrant mode
[occt.git] / src / Standard / Standard_ErrorHandler.cxx
CommitLineData
b311480e 1// Copyright (c) 1998-1999 Matra Datavision
2// Copyright (c) 1999-2012 OPEN CASCADE SAS
3//
4// The content of this file is subject to the Open CASCADE Technology Public
5// License Version 6.5 (the "License"). You may not use the content of this file
6// except in compliance with the License. Please obtain a copy of the License
7// at http://www.opencascade.org and read it completely before using this file.
8//
9// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11//
12// The Original Code and all software distributed under the License is
13// distributed on an "AS IS" basis, without warranty of any kind, and the
14// Initial Developer hereby disclaims all such warranties, including without
15// limitation, any warranties of merchantability, fitness for a particular
16// purpose or non-infringement. Please see the License for the specific terms
17// and conditions governing the rights and limitations under the License.
18
7fd59977 19//============================================================================
20//==== Titre: Standard_ErrorHandler.cxx
21//==== Role : class "Standard_ErrorHandler" implementation.
22//============================================================================
23#include <Standard_ErrorHandler.hxx>
24#include <Standard_Failure.hxx>
25#include <Standard_ErrorHandlerCallback.hxx>
26#include <Standard_Mutex.hxx>
27#include <Standard.hxx>
28
29#ifndef WNT
30#include <pthread.h>
31#else
32#include <windows.h>
33#endif
34
35// ===========================================================================
36// The class "Standard_ErrorHandler" variables
37// ===========================================================================
38
39// During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
40// So if there is an abort request and if K_SETJMP is non zero, the abort
41// request will be ignored. If the abort request do a raise during a setjmp
42// or a longjmp, there will be a "terminating SEGV" impossible to handle.
43
44//==== The top of the Errors Stack ===========================================
45static Standard_ErrorHandler* Top = 0;
46
47// A mutex to protect from concurrent access to Top
48// Note that we should NOT use Sentry while in this class, as Sentry
49// would register mutex as callback in the current exception handler
50static Standard_Mutex theMutex;
51
52static inline Standard_ThreadId GetThreadID()
53{
54#ifndef WNT
55 return pthread_self();
56#else
57 return GetCurrentThreadId();
58#endif
59}
60
61//============================================================================
62//==== Constructor : Create a ErrorHandler structure. And add it at the
63//==== 'Top' of "ErrorHandler's stack".
64//============================================================================
65
66Standard_ErrorHandler::Standard_ErrorHandler () :
67 myStatus(Standard_HandlerVoid), myCallbackPtr(0)
68{
69 myThread = GetThreadID();
70
bd0c22ce 71 theMutex.Lock();
7fd59977 72 myPrevious = Top;
73 Top = this;
bd0c22ce 74 theMutex.Unlock();
7fd59977 75}
76
77
78//============================================================================
79//==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
80//============================================================================
81
82void Standard_ErrorHandler::Destroy()
83{
84 Unlink();
a01039b9 85 if (myStatus == Standard_HandlerJumped)
86 {
87 // jumped, but not caught
88 Abort (myCaughtError);
7fd59977 89 }
90}
91
92
93//=======================================================================
94//function : Unlink
95//purpose :
96//=======================================================================
97
98void Standard_ErrorHandler::Unlink()
99{
100 // put a lock on the stack
bd0c22ce 101 theMutex.Lock();
7fd59977 102
103 Standard_ErrorHandler* aPrevious = 0;
104 Standard_ErrorHandler* aCurrent = Top;
105
106 // locate this handler in the stack
107 while(aCurrent!=0 && this!=aCurrent) {
108 aPrevious = aCurrent;
109 aCurrent = aCurrent->myPrevious;
110 }
111
112 if(aCurrent==0) {
bd0c22ce 113 theMutex.Unlock();
7fd59977 114 return;
115 }
116
117 if(aPrevious==0) {
118 // a top exception taken
119 Top = aCurrent->myPrevious;
120 }
121 else {
122 aPrevious->myPrevious=aCurrent->myPrevious;
123 }
124 myPrevious = 0;
bd0c22ce 125 theMutex.Unlock();
7fd59977 126
127 // unlink and destroy all registered callbacks
128 Standard_Address aPtr = aCurrent->myCallbackPtr;
129 myCallbackPtr = 0;
130 while ( aPtr ) {
131 Standard_ErrorHandlerCallback* aCallback = (Standard_ErrorHandlerCallback*)aPtr;
132 aPtr = aCallback->myNext;
133 // Call destructor explicitly, as we know that it will not be called automatically
134 aCallback->DestroyCallback();
135 }
136}
137
138//=======================================================================
139//function : IsInTryBlock
140//purpose : test if the code is currently running in
141//=======================================================================
142
143Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
144{
145 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
146 return anActive != NULL && anActive->myLabel != NULL;
147}
148
149
150//============================================================================
151//==== Abort: make a longjmp to the saved Context.
152//==== Abort if there is a non null 'Error'
153//============================================================================
154
a01039b9 155void Standard_ErrorHandler::Abort (const Handle(Standard_Failure)& theError)
7fd59977 156{
157 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);
a01039b9 158
7fd59977 159 //==== Check if can do the "longjmp" =======================================
160 if(anActive == NULL || anActive->myLabel == NULL) {
161 cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
a01039b9 162 if (!theError.IsNull())
163 cerr << "\t... The exception is:" << theError->GetMessageString() << endl;
7fd59977 164 exit(1);
165 }
a01039b9 166
7fd59977 167 anActive->myStatus = Standard_HandlerJumped;
168 longjmp(anActive->myLabel, Standard_True);
169}
170
171
172//============================================================================
173//==== Catches: If there is a 'Error', and it is in good type
174//==== returns True and clean 'Error', else returns False.
175//============================================================================
176
177Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
178{
179 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
180 if(anActive==0)
181 return Standard_False;
182
183 if(anActive->myCaughtError.IsNull())
184 return Standard_False;
185
186 if(anActive->myCaughtError->IsKind(AType)){
187 myStatus=Standard_HandlerProcessed;
188 return Standard_True;
189 } else {
190 return Standard_False;
191 }
192}
193
194Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
195{
196 Handle(Standard_Failure) aHandle;
197 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
198 if(anActive!=0)
199 aHandle = anActive->myCaughtError;
200
201 return aHandle;
202}
203
204Handle(Standard_Failure) Standard_ErrorHandler::Error() const
205{
206 return myCaughtError;
207}
208
209
a01039b9 210void Standard_ErrorHandler::Error (const Handle(Standard_Failure)& theError)
7fd59977 211{
a01039b9 212 Standard_ErrorHandler* anActive = FindHandler (Standard_HandlerVoid, Standard_False);
213 if (anActive == NULL)
214 Abort (theError);
7fd59977 215
a01039b9 216 anActive->myCaughtError = theError;
217}
7fd59977 218
219
220Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
221 const Standard_Boolean theUnlink)
222{
223 // lock the stack
bd0c22ce 224 theMutex.Lock();
7fd59977 225
226 // Find the current ErrorHandler Accordin tread
227 Standard_ErrorHandler* aPrevious = 0;
228 Standard_ErrorHandler* aCurrent = Top;
229 Standard_ErrorHandler* anActive = 0;
230 Standard_Boolean aStop = Standard_False;
231 Standard_ThreadId aTreadId = GetThreadID();
232
233 // searching an exception with correct ID number
234 // which is not processed for the moment
235 while(!aStop) {
236 while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
237 aPrevious = aCurrent;
238 aCurrent = aCurrent->myPrevious;
239 }
240
241 if(aCurrent!=NULL) {
242 if(theStatus!=aCurrent->myStatus) {
243
244 if(theUnlink) {
245 //unlink current
246 if(aPrevious==0) {
247 // a top exception taken
248 Top = aCurrent->myPrevious;
249 }
250 else {
251 aPrevious->myPrevious=aCurrent->myPrevious;
252 }
253 }
254
255 //shift
256 aCurrent = aCurrent->myPrevious;
257 }
258 else {
259 //found one
260 anActive = aCurrent;
261 aStop = Standard_True;
262 }
263 }
264 else {
265 //Current is NULL, means that no handlesr
266 aStop = Standard_True;
267 }
268 }
bd0c22ce 269 theMutex.Unlock();
7fd59977 270
271 return anActive;
272}