VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp@ 103140

最後變更 在這個檔案從103140是 102235,由 vboxsync 提交於 16 月 前

libs/xpcom: Remove public PR_Lock and PR_CondVar APIs as they are not used anywhere outside of NSPR, bugref:10545 [build fix]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.2 KB
 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * ActiveState Tool Corp..
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Mark Hammond <[email protected]>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#include "nsISupports.h"
40#include "nsExceptionService.h"
41#include "nsIServiceManager.h"
42#include "nsCOMPtr.h"
43
44#include <iprt/asm.h>
45#include <iprt/errcore.h>
46
47#define CHECK_SERVICE_USE_OK() if (tlsIndex == NIL_RTTLS) return NS_ERROR_NOT_INITIALIZED
48#define CHECK_MANAGER_USE_OK() if (!mService || nsExceptionService::tlsIndex == NIL_RTTLS) return NS_ERROR_NOT_INITIALIZED
49
50// A key for our registered module providers hashtable
51class nsProviderKey : public nsHashKey {
52protected:
53 PRUint32 mKey;
54public:
55 nsProviderKey(PRUint32 key) : mKey(key) {}
56 PRUint32 HashCode(void) const {
57 return mKey;
58 }
59 PRBool Equals(const nsHashKey *aKey) const {
60 return mKey == ((const nsProviderKey *) aKey)->mKey;
61 }
62 nsHashKey *Clone() const {
63 return new nsProviderKey(mKey);
64 }
65 PRUint32 GetValue() { return mKey; }
66};
67
68/** Exception Manager definition **/
69class nsExceptionManager : public nsIExceptionManager
70{
71public:
72 NS_DECL_ISUPPORTS
73 NS_DECL_NSIEXCEPTIONMANAGER
74
75 nsExceptionManager(nsExceptionService *svc);
76 /* additional members */
77 nsCOMPtr<nsIException> mCurrentException;
78 nsExceptionManager *mNextThread; // not ref-counted.
79 nsExceptionService *mService; // not ref-counted
80#ifdef NS_DEBUG
81 static volatile uint32_t totalInstances;
82#endif
83
84#ifdef NS_DEBUG
85 inline nsrefcnt ReleaseQuiet() {
86 // shut up NS_ASSERT_OWNINGTHREAD (see explanation below)
87 nsAutoOwningThread old = _mOwningThread;
88 _mOwningThread = nsAutoOwningThread();
89 nsrefcnt ref = Release();
90 NS_ASSERTION(ref == 0, "the object is still referenced by other threads while it shouldn't");
91 if (ref != 0)
92 _mOwningThread = old;
93 return ref;
94 }
95#else
96 inline nsrefcnt ReleaseQuiet(void) { return Release(); }
97#endif
98
99private:
100 ~nsExceptionManager();
101};
102
103
104#ifdef NS_DEBUG
105volatile uint32_t nsExceptionManager::totalInstances = 0;
106#endif
107
108// Note: the nsExceptionManager object is single threaded - the exception
109// service itself ensures one per thread. However, there are two methods that
110// may be called on foreign threads: DropAllThreads (called on the thread
111// shutting down xpcom) and ThreadDestruct (called after xpcom destroyed the
112// internal thread struct, so that PR_GetCurrentThread() will create a new one
113// from scratch which will obviously not match the old one stored in the
114// instance on creation). In both cases, there should be no other threads
115// holding objects (i.e. it's thread-safe to call them), but
116// NS_CheckThreadSafe() assertions will still happen and yell in the debug
117// build. Since it is quite annoying, we use a special ReleaseQuiet() method
118// in DoDropThread() to shut them up.
119NS_IMPL_THREADSAFE_ISUPPORTS1(nsExceptionManager, nsIExceptionManager)
120
121nsExceptionManager::nsExceptionManager(nsExceptionService *svc) :
122 mNextThread(nsnull),
123 mService(svc)
124{
125 /* member initializers and constructor code */
126#ifdef NS_DEBUG
127 ASMAtomicIncU32(&totalInstances);
128#endif
129}
130
131nsExceptionManager::~nsExceptionManager()
132{
133 /* destructor code */
134#ifdef NS_DEBUG
135 ASMAtomicDecU32(&totalInstances);
136#endif // NS_DEBUG
137}
138
139/* void setCurrentException (in nsIException error); */
140NS_IMETHODIMP nsExceptionManager::SetCurrentException(nsIException *error)
141{
142 CHECK_MANAGER_USE_OK();
143 mCurrentException = error;
144 return NS_OK;
145}
146
147/* nsIException getCurrentException (); */
148NS_IMETHODIMP nsExceptionManager::GetCurrentException(nsIException **_retval)
149{
150 CHECK_MANAGER_USE_OK();
151 *_retval = mCurrentException;
152 NS_IF_ADDREF(*_retval);
153 return NS_OK;
154}
155
156/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */
157NS_IMETHODIMP nsExceptionManager::GetExceptionFromProvider(nsresult rc, nsIException * defaultException, nsIException **_retval)
158{
159 CHECK_MANAGER_USE_OK();
160 // Just delegate back to the service with the provider map.
161 return mService->GetExceptionFromProvider(rc, defaultException, _retval);
162}
163
164/* The Exception Service */
165
166RTTLS nsExceptionService::tlsIndex = NIL_RTTLS;
167RTSEMFASTMUTEX nsExceptionService::lock = NIL_RTSEMFASTMUTEX;
168nsExceptionManager *nsExceptionService::firstThread = nsnull;
169
170#ifdef NS_DEBUG
171volatile uint32_t nsExceptionService::totalInstances = 0;
172#endif
173
174NS_IMPL_THREADSAFE_ISUPPORTS2(nsExceptionService, nsIExceptionService, nsIObserver)
175
176nsExceptionService::nsExceptionService()
177 : mProviders(4, PR_TRUE) /* small, thread-safe hashtable */
178{
179#ifdef NS_DEBUG
180 if (ASMAtomicIncU32(&totalInstances)!=1) {
181 NS_ERROR("The nsExceptionService is a singleton!");
182 }
183#endif
184 /* member initializers and constructor code */
185 if (tlsIndex == NIL_RTTLS) {
186 int vrc = RTTlsAllocEx( &tlsIndex, ThreadDestruct );
187 NS_WARN_IF_FALSE(RT_SUCCESS(vrc), "ScriptErrorService could not allocate TLS storage.");
188 }
189 int vrc = RTSemFastMutexCreate(&lock);
190 NS_WARN_IF_FALSE(RT_SUCCESS(vrc), "Error allocating ExceptionService lock");
191
192 // observe XPCOM shutdown.
193 nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
194 NS_WARN_IF_FALSE(observerService, "Could not get observer service!");
195 if (observerService)
196 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
197}
198
199nsExceptionService::~nsExceptionService()
200{
201 Shutdown();
202 if (lock != NIL_RTSEMFASTMUTEX) {
203 RTSEMFASTMUTEX tmp = lock;
204 lock = NULL;
205 RTSemFastMutexDestroy(tmp);
206 }
207 /* destructor code */
208#ifdef NS_DEBUG
209 ASMAtomicDecU32(&totalInstances);
210#endif
211}
212
213/*static*/
214DECLCALLBACK(void) nsExceptionService::ThreadDestruct( void *data )
215{
216 if (lock == NIL_RTSEMFASTMUTEX) {
217 NS_WARNING("nsExceptionService ignoring thread destruction after shutdown");
218 return;
219 }
220 DropThread( (nsExceptionManager *)data );
221}
222
223
224void nsExceptionService::Shutdown()
225{
226 RTTLS tmp = tlsIndex;
227 tlsIndex = NIL_RTTLS;
228 RTTlsSet(tmp, NULL);
229 mProviders.Reset();
230 if (lock != NIL_RTSEMFASTMUTEX) {
231 DropAllThreads();
232 }
233}
234
235/* void setCurrentException (in nsIException error); */
236NS_IMETHODIMP nsExceptionService::SetCurrentException(nsIException *error)
237{
238 CHECK_SERVICE_USE_OK();
239 nsCOMPtr<nsIExceptionManager> sm;
240 nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm));
241 if (NS_FAILED(nr))
242 return nr;
243 return sm->SetCurrentException(error);
244}
245
246/* nsIException getCurrentException (); */
247NS_IMETHODIMP nsExceptionService::GetCurrentException(nsIException **_retval)
248{
249 CHECK_SERVICE_USE_OK();
250 nsCOMPtr<nsIExceptionManager> sm;
251 nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm));
252 if (NS_FAILED(nr))
253 return nr;
254 return sm->GetCurrentException(_retval);
255}
256
257/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */
258NS_IMETHODIMP nsExceptionService::GetExceptionFromProvider(nsresult rc,
259 nsIException * defaultException, nsIException **_retval)
260{
261 CHECK_SERVICE_USE_OK();
262 return DoGetExceptionFromProvider(rc, defaultException, _retval);
263}
264
265/* readonly attribute nsIExceptionManager currentExceptionManager; */
266NS_IMETHODIMP nsExceptionService::GetCurrentExceptionManager(nsIExceptionManager * *aCurrentScriptManager)
267{
268 CHECK_SERVICE_USE_OK();
269 nsExceptionManager *mgr = (nsExceptionManager *)RTTlsGet(tlsIndex);
270 if (mgr == nsnull) {
271 // Stick the new exception object in with no reference count.
272 mgr = new nsExceptionManager(this);
273 if (mgr == nsnull)
274 return NS_ERROR_OUT_OF_MEMORY;
275 RTTlsSet(tlsIndex, mgr);
276 // The reference count is held in the thread-list
277 AddThread(mgr);
278 }
279 *aCurrentScriptManager = mgr;
280 NS_ADDREF(*aCurrentScriptManager);
281 return NS_OK;
282}
283
284/* void registerErrorProvider (in nsIExceptionProvider provider, in PRUint32 moduleCode); */
285NS_IMETHODIMP nsExceptionService::RegisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule)
286{
287 CHECK_SERVICE_USE_OK();
288
289 nsProviderKey key(errorModule);
290 if (mProviders.Put(&key, provider)) {
291 NS_WARNING("Registration of exception provider overwrote another provider with the same module code!");
292 }
293 return NS_OK;
294}
295
296/* void unregisterErrorProvider (in nsIExceptionProvider provider, in PRUint32 errorModule); */
297NS_IMETHODIMP nsExceptionService::UnregisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule)
298{
299 CHECK_SERVICE_USE_OK();
300 nsProviderKey key(errorModule);
301 if (!mProviders.Remove(&key)) {
302 NS_WARNING("Attempt to unregister an unregistered exception provider!");
303 return NS_ERROR_UNEXPECTED;
304 }
305 return NS_OK;
306}
307
308// nsIObserver
309NS_IMETHODIMP nsExceptionService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
310{
311 Shutdown();
312 return NS_OK;
313}
314
315nsresult
316nsExceptionService::DoGetExceptionFromProvider(nsresult errCode,
317 nsIException * defaultException,
318 nsIException **_exc)
319{
320 // Check for an existing exception
321 nsresult nr = GetCurrentException(_exc);
322 if (NS_SUCCEEDED(nr) && *_exc) {
323 (*_exc)->GetResult(&nr);
324 // If it matches our result then use it
325 if (nr == errCode)
326 return NS_OK;
327 NS_RELEASE(*_exc);
328 }
329 nsProviderKey key(NS_ERROR_GET_MODULE(errCode));
330 nsCOMPtr<nsIExceptionProvider> provider =
331 dont_AddRef((nsIExceptionProvider *)mProviders.Get(&key));
332
333 // No provider so we'll return the default exception
334 if (!provider) {
335 *_exc = defaultException;
336 NS_IF_ADDREF(*_exc);
337 return NS_OK;
338 }
339
340 return provider->GetException(errCode, defaultException, _exc);
341}
342
343// thread management
344/*static*/ void nsExceptionService::AddThread(nsExceptionManager *thread)
345{
346 RTSemFastMutexRequest(lock);
347 thread->mNextThread = firstThread;
348 firstThread = thread;
349 NS_ADDREF(thread);
350 RTSemFastMutexRelease(lock);
351}
352
353/*static*/ void nsExceptionService::DoDropThread(nsExceptionManager *thread)
354{
355 nsExceptionManager **emp = &firstThread;
356 while (*emp != thread) {
357 if (!*emp)
358 {
359 NS_WARNING("Could not find the thread to drop!");
360 return;
361 }
362 emp = &(*emp)->mNextThread;
363 }
364 *emp = thread->mNextThread;
365 thread->ReleaseQuiet();
366 thread = nsnull;
367}
368
369/*static*/ void nsExceptionService::DropThread(nsExceptionManager *thread)
370{
371 RTSemFastMutexRequest(lock);
372 DoDropThread(thread);
373 RTSemFastMutexRelease(lock);
374}
375
376/*static*/ void nsExceptionService::DropAllThreads()
377{
378 RTSemFastMutexRequest(lock);
379 while (firstThread)
380 DoDropThread(firstThread);
381 RTSemFastMutexRelease(lock);
382}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette