From 7ed5ee90fec1d6ee2c7e4bb620b5918879f04c7d Mon Sep 17 00:00:00 2001 From: "bsmedberg%covad.net" Date: Wed, 23 Nov 2005 14:32:18 +0000 Subject: [PATCH] Bug 316414 part 1 - Add "xpcom-shutdown-threads" and "xpcom-shutdown-loaders" notifications during XPCOM Shutdown, r=darin git-svn-id: svn://10.0.0.236/trunk@185199 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/build/nsXPCOMPrivate.h | 12 ++ mozilla/xpcom/build/nsXPComInit.cpp | 73 ++++++++--- mozilla/xpcom/ds/nsObserverList.cpp | 163 ++++++------------------- mozilla/xpcom/ds/nsObserverList.h | 28 +---- mozilla/xpcom/ds/nsObserverService.cpp | 13 +- 5 files changed, 120 insertions(+), 169 deletions(-) diff --git a/mozilla/xpcom/build/nsXPCOMPrivate.h b/mozilla/xpcom/build/nsXPCOMPrivate.h index e99b54e5ce8..7dde7f0a717 100644 --- a/mozilla/xpcom/build/nsXPCOMPrivate.h +++ b/mozilla/xpcom/build/nsXPCOMPrivate.h @@ -53,6 +53,18 @@ class nsStringContainer; class nsCStringContainer; class nsIComponentLoader; +/** + * During this shutdown notification all threads which run XPCOM code must + * be joined. + */ +#define NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID "xpcom-shutdown-threads" + +/** + * During this shutdown notification all module loaders must unload XPCOM + * modules. + */ +#define NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID "xpcom-shutdown-loaders" + /** * Private Method to register an exit routine. This method * allows you to setup a callback that will be called from diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp index 76f48d6d31c..2096c898df2 100644 --- a/mozilla/xpcom/build/nsXPComInit.cpp +++ b/mozilla/xpcom/build/nsXPComInit.cpp @@ -142,7 +142,6 @@ extern void _FreeAutoLockStatics(); static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_CID(kMemoryCID, NS_MEMORY_CID); -static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kINIParserFactoryCID, NS_INIPARSERFACTORY_CID); NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess) @@ -773,11 +772,15 @@ NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) // // The shutdown sequence for xpcom would be // +// - Notify "xpcom-shutdown" for modules to release primary (root) references +// - Notify "xpcom-shutdown-threads" for thread joins +// - Shutdown the main event queue (TODO) // - Release the Global Service Manager // - Release all service instances held by the global service manager // - Release the Global Service Manager itself // - Release the Component Manager // - Release all factories cached by the Component Manager +// - Notify module loaders to shut down // - Unload Libraries // - Release Contractid Cache held by Component Manager // - Release dll abstraction held by Component Manager @@ -787,37 +790,52 @@ NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) EXPORT_XPCOM_API(nsresult) NS_ShutdownXPCOM(nsIServiceManager* servMgr) { + nsresult rv; + + // grab the event queue so that we can process events before exiting. + nsCOMPtr currentQ; + NS_GetCurrentEventQ(getter_AddRefs(currentQ)); + + nsCOMPtr moduleLoaders; // Notify observers of xpcom shutting down - nsresult rv = NS_OK; { // Block it so that the COMPtr will get deleted before we hit // servicemanager shutdown nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1", &rv); - if (NS_SUCCEEDED(rv)) + do_GetService("@mozilla.org/observer-service;1"); + + if (observerService) { nsCOMPtr mgr; rv = NS_GetServiceManager(getter_AddRefs(mgr)); if (NS_SUCCEEDED(rv)) { - (void) observerService->NotifyObservers(mgr, - NS_XPCOM_SHUTDOWN_OBSERVER_ID, - nsnull); + (void) observerService-> + NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID, + nsnull); } } + + if (currentQ) + currentQ->ProcessPendingEvents(); + + if (observerService) + (void) observerService-> + NotifyObservers(nsnull, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, + nsnull); + + if (currentQ) + currentQ->ProcessPendingEvents(); + + // We save the "xpcom-shutdown-loaders" observers to notify after + // the observerservice is gone. + if (observerService) + observerService-> + EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, + getter_AddRefs(moduleLoaders)); } - // grab the event queue so that we can process events one last time before exiting - nsCOMPtr currentQ; - { - nsCOMPtr eventQService = - do_GetService(kEventQueueServiceCID, &rv); - - if (eventQService) { - eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(currentQ)); - } - } // XPCOM is officially in shutdown mode NOW // Set this only after the observers have been notified as this // will cause servicemanager to become inaccessible. @@ -845,6 +863,27 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr) // Release the directory service NS_IF_RELEASE(nsDirectoryService::gService); + if (moduleLoaders) { + PRBool more; + nsCOMPtr el; + while (NS_SUCCEEDED(moduleLoaders->HasMoreElements(&more)) && + more) { + moduleLoaders->GetNext(getter_AddRefs(el)); + + // Don't worry about weak-reference observers here: there is + // no reason for weak-ref observers to register for + // xpcom-shutdown-loaders + + nsCOMPtr obs(do_QueryInterface(el)); + if (obs) + (void) obs->Observe(nsnull, + NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, + nsnull); + } + + moduleLoaders = nsnull; + } + // Shutdown nsLocalFile string conversion NS_ShutdownLocalFile(); #ifdef XP_UNIX diff --git a/mozilla/xpcom/ds/nsObserverList.cpp b/mozilla/xpcom/ds/nsObserverList.cpp index 51fb04b5310..7fbaba63ba8 100644 --- a/mozilla/xpcom/ds/nsObserverList.cpp +++ b/mozilla/xpcom/ds/nsObserverList.cpp @@ -35,100 +35,82 @@ * * ***** END LICENSE BLOCK ***** */ -#define NS_WEAK_OBSERVERS - -#include "pratom.h" -#include "nsString.h" -#include "nsAutoLock.h" -#include "nsCOMPtr.h" -#include "nsIWeakReference.h" -#include "nsEnumeratorUtils.h" #include "nsObserverList.h" -nsObserverList::nsObserverList() +#include "pratom.h" +#include "nsAutoLock.h" +#include "nsIObserver.h" +#include "nsCOMPtr.h" +#include "nsIWeakReference.h" +#include "nsArrayEnumerator.h" + +nsObserverList::nsObserverList(nsresult &rv) { MOZ_COUNT_CTOR(nsObserverList); mLock = PR_NewLock(); + if (!mLock) + rv = NS_ERROR_OUT_OF_MEMORY; } nsObserverList::~nsObserverList(void) { MOZ_COUNT_DTOR(nsObserverList); - PR_DestroyLock(mLock); + if (mLock) + PR_DestroyLock(mLock); } nsresult nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) { - nsresult rv; - PRBool inserted; - NS_ENSURE_ARG(anObserver); nsAutoLock lock(mLock); - if (!mObserverList) { - rv = NS_NewISupportsArray(getter_AddRefs(mObserverList)); - if (NS_FAILED(rv)) return rv; - } - -#ifdef NS_WEAK_OBSERVERS nsCOMPtr observerRef; if (ownsWeak) { nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); NS_ASSERTION(weakRefFactory, "AddObserver: trying weak object that doesnt support nsIWeakReference"); if ( weakRefFactory ) - observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + weakRefFactory-> + GetWeakReference((nsIWeakReference**)(nsISupports**) + getter_AddRefs(observerRef)); } else { -#if DEBUG_dougt_xxx - // if you are hitting this assertion, contact dougt@netscape.com. There may be a ownership problem caused by his checkin to freeze nsIObserver - nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); - NS_ASSERTION(!weakRefFactory, "Your object supports weak references, but is being added with a strong reference"); -#endif observerRef = anObserver; } if (!observerRef) return NS_ERROR_FAILURE; - inserted = mObserverList->AppendElement(observerRef); -#else - if (*anObserver) - inserted = mObserverList->AppendElement(*anObserver); -#endif - return inserted ? NS_OK : NS_ERROR_FAILURE; + if (!mObservers.AppendObject(observerRef)) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; } nsresult nsObserverList::RemoveObserver(nsIObserver* anObserver) { - PRBool removed = PR_FALSE; - NS_ENSURE_ARG(anObserver); nsAutoLock lock(mLock); - if (!mObserverList) - return NS_ERROR_FAILURE; - -#ifdef NS_WEAK_OBSERVERS - nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); - nsCOMPtr observerRef; - if (weakRefFactory) { - observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); - if (observerRef) - removed = mObserverList->RemoveElement(observerRef); - if (!removed) - observerRef = anObserver; - } else - observerRef = anObserver; + if (mObservers.RemoveObject(anObserver)) + return NS_OK; - if (!removed && observerRef) - removed = mObserverList->RemoveElement(observerRef); -#else - if (*anObserver) - removed = mObserverList->RemoveElement(*anObserver); -#endif - return removed ? NS_OK : NS_ERROR_FAILURE; + nsCOMPtr + weakRefFactory(do_QueryInterface(anObserver)); + if (!weakRefFactory) + return NS_ERROR_FAILURE; + + nsCOMPtr observerRef; + weakRefFactory->GetWeakReference(getter_AddRefs(observerRef)); + + if (!observerRef) + return NS_ERROR_FAILURE; + + if (!mObservers.RemoveObject(observerRef)) + return NS_ERROR_FAILURE; + + return NS_OK; } nsresult @@ -136,76 +118,5 @@ nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) { nsAutoLock lock(mLock); - ObserverListEnumerator * enumerator= new ObserverListEnumerator(mObserverList); - *anEnumerator = enumerator; - if (!enumerator) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(enumerator); - return NS_OK; -} - - -ObserverListEnumerator::ObserverListEnumerator(nsISupportsArray* aValueArray) - : mValueArray(aValueArray), mIndex(0) -{ - if (mValueArray) { - NS_ADDREF(mValueArray); - PRUint32 total; - mValueArray->Count(&total); - mIndex = PRInt32(total); - } -} - -ObserverListEnumerator::~ObserverListEnumerator(void) -{ - NS_IF_RELEASE(mValueArray); -} - -NS_IMPL_ISUPPORTS1(ObserverListEnumerator, nsISimpleEnumerator) - -NS_IMETHODIMP -ObserverListEnumerator::HasMoreElements(PRBool* aResult) -{ - NS_PRECONDITION(aResult != 0, "null ptr"); - if (! aResult) - return NS_ERROR_NULL_POINTER; - - if (!mValueArray) { - *aResult = PR_FALSE; - return NS_OK; - } - - *aResult = (mIndex > 0); - return NS_OK; -} - -NS_IMETHODIMP -ObserverListEnumerator::GetNext(nsISupports** aResult) -{ - NS_PRECONDITION(aResult != 0, "null ptr"); - if (! aResult) - return NS_ERROR_NULL_POINTER; - - if (!mValueArray) { - *aResult = nsnull; - return NS_OK; - } - - if (mIndex <= 0 ) - return NS_ERROR_UNEXPECTED; - - mValueArray->GetElementAt(--mIndex, aResult); - if (*aResult) { - nsCOMPtr weakRefFactory = do_QueryInterface(*aResult); - if ( weakRefFactory ) { - nsCOMPtr weakref = do_QueryReferent(weakRefFactory); - NS_RELEASE(*aResult); - NS_IF_ADDREF(*aResult = weakref); - - return NS_OK; - } - } - - return NS_OK; + return NS_NewArrayEnumerator(anEnumerator, mObservers); } diff --git a/mozilla/xpcom/ds/nsObserverList.h b/mozilla/xpcom/ds/nsObserverList.h index 521ce1c80bd..6706cae65b7 100644 --- a/mozilla/xpcom/ds/nsObserverList.h +++ b/mozilla/xpcom/ds/nsObserverList.h @@ -38,32 +38,16 @@ #ifndef nsObserverList_h___ #define nsObserverList_h___ -#include "nsIObserver.h" -#include "nsIEnumerator.h" -#include "nsISupportsArray.h" -#include "nsISimpleEnumerator.h" +#include "nsISupports.h" +#include "nsCOMArray.h" -class ObserverListEnumerator : public nsISimpleEnumerator -{ -public: - // nsISupports interface - NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR - - ObserverListEnumerator(nsISupportsArray* aValueArray); - -private: - ~ObserverListEnumerator(void); - -protected: - nsISupportsArray* mValueArray; - PRInt32 mIndex; -}; +class nsISimpleEnumerator; +class nsIObserver; class nsObserverList { public: - nsObserverList(); + nsObserverList(nsresult &rv); ~nsObserverList(); nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak); @@ -72,7 +56,7 @@ public: protected: PRLock* mLock; - nsCOMPtr mObserverList; + nsCOMArray mObservers; }; diff --git a/mozilla/xpcom/ds/nsObserverService.cpp b/mozilla/xpcom/ds/nsObserverService.cpp index 110cfd6ddb8..8d5d923b06c 100644 --- a/mozilla/xpcom/ds/nsObserverService.cpp +++ b/mozilla/xpcom/ds/nsObserverService.cpp @@ -42,12 +42,13 @@ #include "nsIServiceManager.h" #include "nsIComponentManager.h" #include "nsIObserverService.h" +#include "nsIObserver.h" +#include "nsISimpleEnumerator.h" #include "nsObserverService.h" #include "nsObserverList.h" #include "nsHashtable.h" #include "nsIWeakReference.h" -#define NS_WEAK_OBSERVERS #define NOTIFY_GLOBAL_OBSERVERS #if defined(PR_LOGGING) @@ -135,9 +136,15 @@ nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** return NS_OK; } - topicObservers = new nsObserverList(); + nsresult rv = NS_OK; + topicObservers = new nsObserverList(rv); if (!topicObservers) return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv)) { + delete topicObservers; + return rv; + } *anObserverList = topicObservers; mObserverTopicTable->Put(&key, topicObservers); @@ -231,7 +238,6 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, nsCOMPtr observer = do_QueryInterface(observerRef); if (observer) observer->Observe(aSubject, aTopic, someData); -#ifdef NS_WEAK_OBSERVERS else { // check for weak reference. nsCOMPtr weakRef = do_QueryInterface(observerRef); @@ -244,7 +250,6 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, PR_LOG(observerServiceLog, PR_LOG_DEBUG, ("Notification - %s\n", aTopic ? aTopic : "undefined")); } -#endif } } while (observers); return NS_OK;