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 =========================================== |
45 | static 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 |
50 | static Standard_Mutex theMutex; |
51 | |
52 | static 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 | |
66 | Standard_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 | |
82 | void 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 | |
98 | void 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 | |
143 | Standard_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 |
155 | void 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 | |
177 | Standard_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 | |
194 | Handle(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 | |
204 | Handle(Standard_Failure) Standard_ErrorHandler::Error() const |
205 | { |
206 | return myCaughtError; |
207 | } |
208 | |
209 | |
a01039b9 |
210 | void 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 | |
220 | Standard_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 | } |