diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 76f48d6d31c..8bd25cf2e78 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -72,6 +72,7 @@ #include "nsEventQueueService.h" #include "nsEventQueue.h" +#include "nsEventQueueUtils.h" #include "nsIProxyObjectManager.h" #include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration. @@ -142,7 +143,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 +773,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 +791,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 +864,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/xpcom/ds/nsArrayEnumerator.cpp b/xpcom/ds/nsArrayEnumerator.cpp index 243ba8657f3..7094362f418 100644 --- a/xpcom/ds/nsArrayEnumerator.cpp +++ b/xpcom/ds/nsArrayEnumerator.cpp @@ -112,7 +112,8 @@ public: } // specialized operator to make sure we make room for mValues - void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW; + void* operator new (size_t size, const nsCOMArray_base& aArray, + PRBool aReverse) CPP_THROW_NEW; void operator delete(void* ptr) { ::operator delete(ptr); } @@ -172,7 +173,8 @@ nsCOMArrayEnumerator::GetNext(nsISupports** aResult) } void* -nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) +nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray, + PRBool aReverse) CPP_THROW_NEW { // create enough space such that mValueArray points to a large @@ -184,15 +186,20 @@ nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) nsCOMArrayEnumerator * result = NS_STATIC_CAST(nsCOMArrayEnumerator*, ::operator new(size)); + if (!result) + return result; + // now need to copy over the values, and addref each one // now this might seem like a lot of work, but we're actually just // doing all our AddRef's ahead of time since GetNext() doesn't // need to AddRef() on the way out - PRUint32 i; PRUint32 max = result->mArraySize = aArray.Count(); - for (i = 0; imValueArray[i] = aArray[i]; - NS_IF_ADDREF(result->mValueArray[i]); + PRUint32 cur = aReverse ? max - 1 : 0; + PRUint32 incr = aReverse ? -1 : 1; + + for (PRUint32 i = 0; i < max; ++i, cur += incr) { + result->mValueArray[cur] = aArray[i]; + NS_IF_ADDREF(result->mValueArray[cur]); } return result; @@ -200,9 +207,11 @@ nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) extern NS_COM nsresult NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, - const nsCOMArray_base& aArray) + const nsCOMArray_base& aArray, + PRBool aReverse) { - nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator(); + nsCOMArrayEnumerator *enumerator = + new (aArray, aReverse) nsCOMArrayEnumerator(); if (!enumerator) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aResult = enumerator); diff --git a/xpcom/ds/nsArrayEnumerator.h b/xpcom/ds/nsArrayEnumerator.h index 8595b9fd4df..a1b65266d7f 100644 --- a/xpcom/ds/nsArrayEnumerator.h +++ b/xpcom/ds/nsArrayEnumerator.h @@ -82,6 +82,7 @@ NS_NewArrayEnumerator(nsISimpleEnumerator* *result, // without its objects going away. extern NS_COM nsresult NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, - const nsCOMArray_base& aArray); + const nsCOMArray_base& aArray, + PRBool aReverse = PR_FALSE); #endif diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index 38e50708b0a..87049e42e49 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -35,100 +35,84 @@ * * ***** 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 doesn't support nsIWeakReference"); - if ( weakRefFactory ) - observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + nsCOMPtr + weakRefFactory(do_QueryInterface(anObserver)); + NS_ASSERTION(weakRefFactory, + "Doesn't implement nsISupportsWeakReference"); + if (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 +120,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, PR_TRUE); } diff --git a/xpcom/ds/nsObserverList.h b/xpcom/ds/nsObserverList.h index 521ce1c80bd..6706cae65b7 100644 --- a/xpcom/ds/nsObserverList.h +++ b/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/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index 110cfd6ddb8..8d5d923b06c 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/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;