From ff6cab48ca52fa265b6468dd457e49fdf0ea1be0 Mon Sep 17 00:00:00 2001 From: "bsmedberg%covad.net" Date: Tue, 11 May 2004 09:38:50 +0000 Subject: [PATCH] Allow XPCOM to be restarted. r+sr=darin with grudging consent from dougt. Bug 239819 git-svn-id: svn://10.0.0.236/trunk@156232 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/build/nsXPComInit.cpp | 15 ++--- mozilla/xpcom/threads/TimerThread.cpp | 84 +++++++++++++++++++-------- mozilla/xpcom/threads/TimerThread.h | 8 ++- mozilla/xpcom/threads/nsThread.cpp | 1 + mozilla/xpcom/threads/nsTimerImpl.cpp | 60 +++++++++---------- mozilla/xpcom/threads/nsTimerImpl.h | 3 +- 6 files changed, 100 insertions(+), 71 deletions(-) diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp index b3651e708c7..e61f2f75c1a 100644 --- a/mozilla/xpcom/build/nsXPComInit.cpp +++ b/mozilla/xpcom/build/nsXPComInit.cpp @@ -265,12 +265,6 @@ nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL; nsIProperties *gDirectoryService = NULL; PRBool gXPCOMShuttingDown = PR_FALSE; -// If XPCOM is unloaded, we need a way to ensure that all statics have been -// reinitalized when reloading. Here we create a boolean which is initialized -// to true. During shutdown, this boolean with set to false. When we startup, -// this boolean will be checked and if the value is not true, startup will fail. -static PRBool gXPCOMHasGlobalsBeenInitalized = PR_TRUE; - // For each class that wishes to support nsIClassInfo, add a line like this // NS_DECL_CLASSINFO(nsMyClass) @@ -425,10 +419,6 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, nsIFile* binDirectory, nsIDirectoryServiceProvider* appFileLocationProvider) { - - if (!gXPCOMHasGlobalsBeenInitalized) - return NS_ERROR_NOT_INITIALIZED; - nsresult rv = NS_OK; // We are not shutting down @@ -442,6 +432,10 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, rv = nsIThread::SetMainThread(); if (NS_FAILED(rv)) return rv; + // Set up the timer globals/timer thread + rv = nsTimerImpl::Startup(); + NS_ENSURE_SUCCESS(rv, rv); + // Startup the memory manager rv = nsMemoryImpl::Startup(); if (NS_FAILED(rv)) return rv; @@ -842,7 +836,6 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) NS_ShutdownLeakDetector(); #endif - gXPCOMHasGlobalsBeenInitalized = PR_FALSE; return NS_OK; } diff --git a/mozilla/xpcom/threads/TimerThread.cpp b/mozilla/xpcom/threads/TimerThread.cpp index 9bed79cee02..bd831148190 100644 --- a/mozilla/xpcom/threads/TimerThread.cpp +++ b/mozilla/xpcom/threads/TimerThread.cpp @@ -50,6 +50,8 @@ NS_IMPL_THREADSAFE_ISUPPORTS3(TimerThread, nsIRunnable, nsISupportsWeakReference, nsIObserver) TimerThread::TimerThread() : + mInitInProgress(0), + mInitialized(PR_FALSE), mLock(nsnull), mCondVar(nsnull), mShutdown(PR_FALSE), @@ -84,11 +86,10 @@ TimerThread::~TimerThread() } -nsresult TimerThread::Init() +nsresult +TimerThread::InitLocks() { - if (mThread) - return NS_OK; - + NS_ASSERTION(!mLock, "InitLocks called twice?"); mLock = PR_NewLock(); if (!mLock) return NS_ERROR_OUT_OF_MEMORY; @@ -97,29 +98,62 @@ nsresult TimerThread::Init() if (!mCondVar) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv; - mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv); - if (NS_FAILED(rv)) - return rv; + return NS_OK; +} - // We hold on to mThread to keep the thread alive. - rv = NS_NewThread(getter_AddRefs(mThread), - NS_STATIC_CAST(nsIRunnable*, this), - 0, - PR_JOINABLE_THREAD, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD); - if (NS_FAILED(rv)) - return rv; +nsresult TimerThread::Init() +{ + if (mInitialized) { + if (!mThread) + return NS_ERROR_FAILURE; - nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); - if (NS_FAILED(rv)) - return rv; - - observerService->AddObserver(this, "sleep_notification", PR_TRUE); - observerService->AddObserver(this, "wake_notification", PR_TRUE); - - return rv; + return NS_OK; + } + + if (PR_AtomicSet(&mInitInProgress, 1) == 0) { + nsresult rv; + + mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr observerService + (do_GetService("@mozilla.org/observer-service;1", &rv)); + + if (NS_SUCCEEDED(rv)) { + // We hold on to mThread to keep the thread alive. + rv = NS_NewThread(getter_AddRefs(mThread), + NS_STATIC_CAST(nsIRunnable*, this), + 0, + PR_JOINABLE_THREAD, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD); + + if (NS_FAILED(rv)) { + mThread = nsnull; + } + else { + observerService->AddObserver(this, "sleep_notification", PR_TRUE); + observerService->AddObserver(this, "wake_notification", PR_TRUE); + } + } + } + + PR_Lock(mLock); + mInitialized = PR_TRUE; + PR_NotifyAllCondVar(mCondVar); + PR_Unlock(mLock); + } + else { + PR_Lock(mLock); + while (!mInitialized) { + PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mLock); + } + + if (!mThread) + return NS_ERROR_FAILURE; + + return NS_OK; } nsresult TimerThread::Shutdown() diff --git a/mozilla/xpcom/threads/TimerThread.h b/mozilla/xpcom/threads/TimerThread.h index 569c610e9ed..fa23cfc9ab2 100644 --- a/mozilla/xpcom/threads/TimerThread.h +++ b/mozilla/xpcom/threads/TimerThread.h @@ -62,13 +62,14 @@ class TimerThread : public nsSupportsWeakReference, { public: TimerThread(); + NS_HIDDEN_(nsresult) InitLocks(); NS_DECL_ISUPPORTS NS_DECL_NSIRUNNABLE NS_DECL_NSIOBSERVER - nsresult Init(); - nsresult Shutdown(); + NS_HIDDEN_(nsresult) Init(); + NS_HIDDEN_(nsresult) Shutdown(); nsresult AddTimer(nsTimerImpl *aTimer); nsresult TimerDelayChanged(nsTimerImpl *aTimer); @@ -89,6 +90,9 @@ public: private: ~TimerThread(); + PRInt32 mInitInProgress; + PRBool mInitialized; + // These two internal helper methods must be called while mLock is held. // AddTimerInternal returns the position where the timer was added in the // list, or -1 if it failed. diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index 72b3b4be94e..2a0c8e15023 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -437,6 +437,7 @@ nsThread::Shutdown() nsrefcnt cnt; NS_RELEASE2(gMainThread, cnt); NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown."); + gMainThread = nsnull; kIThreadSelfIndex = 0; } diff --git a/mozilla/xpcom/threads/nsTimerImpl.cpp b/mozilla/xpcom/threads/nsTimerImpl.cpp index 9e196451733..dc19452fa42 100644 --- a/mozilla/xpcom/threads/nsTimerImpl.cpp +++ b/mozilla/xpcom/threads/nsTimerImpl.cpp @@ -46,14 +46,13 @@ #include "nsIEventQueue.h" +#include "prmem.h" + static PRInt32 gGenerator = 0; static TimerThread* gThread = nsnull; static PRBool gFireOnIdle = PR_FALSE; static nsTimerManager* gManager = nsnull; -#include "prmem.h" -#include "prinit.h" - #ifdef DEBUG_TIMERS #include @@ -139,23 +138,6 @@ NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void) return count; } -PR_STATIC_CALLBACK(PRStatus) InitThread(void) -{ - gThread = new TimerThread(); - if (!gThread) - return PR_FAILURE; - - NS_ADDREF(gThread); - - nsresult rv = gThread->Init(); - if (NS_FAILED(rv)) { - NS_RELEASE(gThread); - return PR_FAILURE; - } - - return PR_SUCCESS; -} - nsTimerImpl::nsTimerImpl() : mClosure(nsnull), mCallbackType(CALLBACK_TYPE_UNKNOWN), @@ -167,11 +149,9 @@ nsTimerImpl::nsTimerImpl() : mDelay(0), mTimeout(0) { + // XXXbsmedberg: shouldn't this be in Init()? nsIThread::GetCurrent(getter_AddRefs(mCallingThread)); - static PRCallOnceType once; - PR_CallOnce(&once, InitThread); - mCallback.c = nsnull; #ifdef DEBUG_TIMERS @@ -185,6 +165,24 @@ nsTimerImpl::~nsTimerImpl() ReleaseCallback(); } +//static +nsresult +nsTimerImpl::Startup() +{ + nsresult rv; + + gThread = new TimerThread(); + if (!gThread) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(gThread); + rv = gThread->InitLocks(); + + if (NS_FAILED(rv)) { + NS_RELEASE(gThread); + } + + return rv; +} void nsTimerImpl::Shutdown() { @@ -210,6 +208,13 @@ void nsTimerImpl::Shutdown() nsresult nsTimerImpl::InitCommon(PRUint32 aType, PRUint32 aDelay) { + nsresult rv; + + NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); + + rv = gThread->Init(); + NS_ENSURE_SUCCESS(rv, rv); + /** * In case of re-Init, both with and without a preceding Cancel, clear the * mCanceled flag and assign a new mGeneration. But first, remove any armed @@ -240,9 +245,6 @@ NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc, PRUint32 aDelay, PRUint32 aType) { - if (!gThread) - return NS_ERROR_FAILURE; - ReleaseCallback(); mCallbackType = CALLBACK_TYPE_FUNC; mCallback.c = aFunc; @@ -255,9 +257,6 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback, PRUint32 aDelay, PRUint32 aType) { - if (!gThread) - return NS_ERROR_FAILURE; - ReleaseCallback(); mCallbackType = CALLBACK_TYPE_INTERFACE; mCallback.i = aCallback; @@ -270,9 +269,6 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver, PRUint32 aDelay, PRUint32 aType) { - if (!gThread) - return NS_ERROR_FAILURE; - ReleaseCallback(); mCallbackType = CALLBACK_TYPE_OBSERVER; mCallback.o = aObserver; diff --git a/mozilla/xpcom/threads/nsTimerImpl.h b/mozilla/xpcom/threads/nsTimerImpl.h index 41e8b511e18..98596f4e918 100644 --- a/mozilla/xpcom/threads/nsTimerImpl.h +++ b/mozilla/xpcom/threads/nsTimerImpl.h @@ -91,7 +91,8 @@ public: nsTimerImpl(); - static void Shutdown(); + static NS_HIDDEN_(nsresult) Startup(); + static NS_HIDDEN_(void) Shutdown(); friend class TimerThread;