mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Allow XPCOM to be restarted. r+sr=darin with grudging consent from dougt. Bug 239819
This commit is contained in:
parent
1c72160e55
commit
fbe50a0568
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -91,7 +91,8 @@ public:
|
||||
|
||||
nsTimerImpl();
|
||||
|
||||
static void Shutdown();
|
||||
static NS_HIDDEN_(nsresult) Startup();
|
||||
static NS_HIDDEN_(void) Shutdown();
|
||||
|
||||
friend class TimerThread;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user