Allow XPCOM to be restarted. r+sr=darin with grudging consent from dougt. Bug 239819

This commit is contained in:
bsmedberg%covad.net 2004-05-11 09:38:50 +00:00
parent 1c72160e55
commit fbe50a0568
6 changed files with 100 additions and 71 deletions

View File

@ -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;
}

View File

@ -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<nsIObserverService> 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<nsIObserverService> 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()

View File

@ -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.

View File

@ -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;
}

View File

@ -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 <math.h>
@ -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;

View File

@ -91,7 +91,8 @@ public:
nsTimerImpl();
static void Shutdown();
static NS_HIDDEN_(nsresult) Startup();
static NS_HIDDEN_(void) Shutdown();
friend class TimerThread;