0030895: Coding Rules - specify std namespace explicitly for std::cout and streams
[occt.git] / src / Standard / Standard_ErrorHandler.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
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.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
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_Mutex.hxx>
22 #include <Standard.hxx>
23
24 #ifndef _WIN32
25 #include <pthread.h>
26 #else
27 #include <windows.h>
28 #endif
29
30 // ===========================================================================
31 // The class "Standard_ErrorHandler" variables
32 // ===========================================================================
33
34 // During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
35 // So if there is an abort request and if K_SETJMP is non zero, the abort
36 // request will be ignored. If the abort request do a raise during a setjmp
37 // or a longjmp, there will be a "terminating SEGV" impossible to handle.
38
39 //==== The top of the Errors Stack ===========================================
40 static Standard_ErrorHandler* Top = 0;
41
42 // A mutex to protect from concurrent access to Top
43 // Note that we should NOT use Sentry while in this class, as Sentry
44 // would register mutex as callback in the current exception handler
45 static Standard_Mutex theMutex; 
46
47 static inline Standard_ThreadId GetThreadID()
48 {
49 #ifndef _WIN32
50   return (Standard_ThreadId)pthread_self();
51 #else
52   return GetCurrentThreadId();
53 #endif
54 }
55
56 //============================================================================
57 //====  Constructor : Create a ErrorHandler structure. And add it at the 
58 //====                'Top' of "ErrorHandler's stack".
59 //============================================================================
60
61 Standard_ErrorHandler::Standard_ErrorHandler () : 
62        myStatus(Standard_HandlerVoid), myCallbackPtr(0)
63 {
64   myThread   = GetThreadID();
65   memset (&myLabel, 0, sizeof(myLabel));
66
67   theMutex.Lock();
68   myPrevious = Top;
69   Top        = this;
70   theMutex.Unlock();
71 }
72
73
74 //============================================================================
75 //==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
76 //============================================================================
77
78 void Standard_ErrorHandler::Destroy()
79 {
80   Unlink();
81   if (myStatus == Standard_HandlerJumped)
82   {
83     // jumped, but not caught
84     Abort (myCaughtError);
85   }
86 }
87
88
89 //=======================================================================
90 //function : Unlink
91 //purpose  : 
92 //=======================================================================
93
94 void Standard_ErrorHandler::Unlink()
95 {
96   // put a lock on the stack
97   theMutex.Lock();
98   
99   Standard_ErrorHandler* aPrevious = 0;
100   Standard_ErrorHandler* aCurrent = Top;
101   
102   // locate this handler in the stack
103   while(aCurrent!=0 && this!=aCurrent) {
104     aPrevious = aCurrent;
105     aCurrent = aCurrent->myPrevious;
106   }
107   
108   if(aCurrent==0) {
109     theMutex.Unlock();
110     return;
111   }
112   
113   if(aPrevious==0) {
114     // a top exception taken
115     Top = aCurrent->myPrevious;
116   }
117   else {
118     aPrevious->myPrevious=aCurrent->myPrevious;
119   }
120   myPrevious = 0;
121   theMutex.Unlock();
122
123   // unlink and destroy all registered callbacks
124   Standard_Address aPtr = aCurrent->myCallbackPtr;
125   myCallbackPtr = 0;
126   while ( aPtr ) {
127     Standard_ErrorHandler::Callback* aCallback = (Standard_ErrorHandler::Callback*)aPtr;
128     aPtr = aCallback->myNext;
129     // Call destructor explicitly, as we know that it will not be called automatically
130     aCallback->DestroyCallback();
131   }
132 }
133
134 //=======================================================================
135 //function : IsInTryBlock
136 //purpose  :  test if the code is currently running in
137 //=======================================================================
138
139 Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
140 {
141   Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
142   return anActive != NULL;
143 }
144
145
146 //============================================================================
147 //==== Abort: make a longjmp to the saved Context.
148 //====    Abort if there is a non null 'Error'
149 //============================================================================
150
151 void Standard_ErrorHandler::Abort (const Handle(Standard_Failure)& theError)
152 {
153   Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);
154
155   //==== Check if can do the "longjmp" =======================================
156   if(anActive == NULL) {
157     std::cerr << "*** Abort *** an exception was raised, but no catch was found." << std::endl;
158     if (!theError.IsNull())
159       std::cerr << "\t... The exception is:" << theError->GetMessageString() << std::endl;
160     exit(1);
161   }
162
163   anActive->myStatus = Standard_HandlerJumped;
164   longjmp(anActive->myLabel, Standard_True);
165 }
166
167
168 //============================================================================
169 //==== Catches: If there is a 'Error', and it is in good type 
170 //====          returns True and clean 'Error', else returns False.
171 //============================================================================
172
173 Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType) 
174 {
175   Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
176   if(anActive==0)
177     return Standard_False;
178   
179   if(anActive->myCaughtError.IsNull())
180     return Standard_False;
181
182   if(anActive->myCaughtError->IsKind(AType)){
183     myStatus=Standard_HandlerProcessed;
184     return Standard_True;
185   } else {
186     return Standard_False;
187   }
188 }
189
190 Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
191 {
192   Handle(Standard_Failure) aHandle;
193   Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
194   if(anActive!=0) 
195     aHandle = anActive->myCaughtError;
196   
197   return aHandle;
198 }
199
200 Handle(Standard_Failure) Standard_ErrorHandler::Error() const
201 {
202   return myCaughtError;
203 }
204
205
206 void Standard_ErrorHandler::Error (const Handle(Standard_Failure)& theError)
207 {
208   Standard_ErrorHandler* anActive = FindHandler (Standard_HandlerVoid, Standard_False);
209   if (anActive == NULL)
210     Abort (theError);
211
212   anActive->myCaughtError = theError;
213 }
214
215
216 Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
217                                                           const Standard_Boolean theUnlink)
218 {
219   // lock the stack
220   theMutex.Lock();
221     
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();
228   
229   // searching an exception with correct ID number
230   // which is not processed for the moment
231   while(!aStop) {
232     while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
233       aPrevious = aCurrent;
234       aCurrent = aCurrent->myPrevious;
235     }
236     
237     if(aCurrent!=NULL) {
238       if(theStatus!=aCurrent->myStatus) {
239         
240         if(theUnlink) {
241           //unlink current
242           if(aPrevious==0) {
243             // a top exception taken
244             Top = aCurrent->myPrevious;
245           }
246           else {
247             aPrevious->myPrevious=aCurrent->myPrevious;
248           }
249         }
250         
251         //shift
252         aCurrent = aCurrent->myPrevious;
253       }
254       else {
255         //found one
256         anActive = aCurrent;
257         aStop = Standard_True;
258       }
259     }
260     else {
261       //Current is NULL, means that no handlesr
262       aStop = Standard_True;
263     }
264   }
265   theMutex.Unlock();
266   
267   return anActive;
268 }
269
270 #if defined(OCC_CONVERT_SIGNALS)
271
272 Standard_ErrorHandler::Callback::Callback ()
273   : myHandler(0), myPrev(0), myNext(0)
274 {
275 }
276
277 Standard_ErrorHandler::Callback::~Callback ()
278 {
279   UnregisterCallback();
280 }
281
282 void Standard_ErrorHandler::Callback::RegisterCallback ()
283 {
284   if ( myHandler ) return; // already registered
285
286   // find current active exception handler
287   Standard_ErrorHandler *aHandler =
288     Standard_ErrorHandler::FindHandler(Standard_HandlerVoid, Standard_False);
289
290   // if found, add this callback object first to the list
291   if ( aHandler ) {
292     myHandler = aHandler;
293     myNext = aHandler->myCallbackPtr;
294     if ( myNext ) ((Standard_ErrorHandler::Callback*)myNext)->myPrev = this;
295     aHandler->myCallbackPtr = this;
296   }
297 }
298
299 void Standard_ErrorHandler::Callback::UnregisterCallback ()
300 {
301   if ( ! myHandler ) return;
302   if ( myNext )
303     ((Standard_ErrorHandler::Callback*)myNext)->myPrev = myPrev;
304   if ( myPrev )
305     ((Standard_ErrorHandler::Callback*)myPrev)->myNext = myNext;
306   else if ( ((Standard_ErrorHandler*)myHandler)->myCallbackPtr == this)
307     ((Standard_ErrorHandler*)myHandler)->myCallbackPtr = (Standard_ErrorHandler::Callback*)myNext;
308   myHandler = myNext = myPrev = 0;
309 }
310 #endif