root-threads
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 96 91c1b7c9ad098a4138c70c9203c96ff5f7beb920
permissions -rw-r--r--
State as of now

diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -63,7 +63,7 @@ AppendAndRemoveThread(const void *key, n
 
 //-----------------------------------------------------------------------------
 
-nsThreadManager* nsThreadManager::gInstance;
+nsThreadManager::Root* nsThreadManager::gInstance;
 
 // statically allocated instance
 NS_IMPL_QUERY_INTERFACE1_CI(nsThreadManager, nsIThreadManager)
@@ -162,6 +162,8 @@ nsThreadManager::Shutdown()
   // We don't need this lock anymore.
   PR_DestroyLock(mLock);
   mLock = nsnull;
+  delete gInstance;
+  gInstance = nsnull;
 }
 
 void
@@ -173,7 +175,6 @@ nsThreadManager::RegisterCurrentThread(n
 
   mThreadsByPRThread.Put(thread->GetPRThread(), thread);  // XXX check OOM?
 
-  NS_ADDREF(thread);  // for TLS entry
   PR_SetThreadPrivate(mCurThreadIndex, thread);
 }
 
@@ -203,11 +204,11 @@ nsThreadManager::GetCurrentThread()
   }
 
   // OK, that's fine.  We'll dynamically create one :-)
-  nsRefPtr<nsThread> thread = new nsThread();
+  nsThread* thread = new nsThread();
   if (!thread || NS_FAILED(thread->InitCurrentThread()))
     return nsnull;
 
-  return thread.get();  // reference held in TLS
+  return thread;  // reference held in TLS
 }
 
 NS_IMETHODIMP
@@ -219,7 +220,6 @@ nsThreadManager::NewThread(PRUint32 crea
   nsThread *thr = new nsThread();
   if (!thr)
     return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(thr);
 
   nsresult rv = thr->Init();
   if (NS_FAILED(rv)) {
@@ -242,13 +242,13 @@ nsThreadManager::GetThreadFromPRThread(P
   NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED);
   NS_ENSURE_ARG_POINTER(thread);
 
-  nsRefPtr<nsThread> temp;
+  nsThread* temp = nsnull;
   {
     nsAutoLock lock(mLock);
-    mThreadsByPRThread.Get(thread, getter_AddRefs(temp));
+    mThreadsByPRThread.Get(thread, &temp);
   }
 
-  NS_IF_ADDREF(*result = temp);
+  *result = temp;
   return NS_OK;
 }
 
@@ -257,7 +257,7 @@ nsThreadManager::GetMainThread(nsIThread
 {
   // Keep this functioning during Shutdown
   NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED);
-  NS_ADDREF(*result = mMainThread);
+  *result = mMainThread;
   return NS_OK;
 }
 
@@ -269,7 +269,6 @@ nsThreadManager::GetCurrentThread(nsIThr
   *result = GetCurrentThread();
   if (!*result)
     return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(*result);
   return NS_OK;
 }
 
diff --git a/xpcom/threads/nsThreadManager.h b/xpcom/threads/nsThreadManager.h
--- a/xpcom/threads/nsThreadManager.h
+++ b/xpcom/threads/nsThreadManager.h
@@ -53,9 +53,9 @@ public:
 
   static nsThreadManager *get() {
     if (!gInstance) {
-      gInstance = new nsThreadManager;
+      gInstance = new nsThreadManager::Root();
     }
-    return gInstance;
+    return gInstance->instance;
   }
 
   nsresult Init();
@@ -88,9 +88,20 @@ private:
     , mInitialized(PR_FALSE) {
   }
   
-  static nsThreadManager *gInstance;
+  class Root : public MMgc::GCRoot
+  {
+  public:
+    Root()
+      : MMgc::GCRoot(NS_GetGC())
+      , instance(new nsThreadManager()) { }
+      
 
-  nsRefPtrHashtable<nsVoidPtrHashKey, nsThread> mThreadsByPRThread;
+    nsThreadManager *instance;
+  };
+
+  static Root *gInstance;
+
+  nsRefPtrHashtable<nsVoidPtrHashKey, nsThread, GCAllocator> mThreadsByPRThread;
   PRUintn             mCurThreadIndex;  // thread-local-storage index
   nsRefPtr<nsThread>  mMainThread;
   PRThread           *mMainPRThread;
diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -48,7 +48,6 @@
 #include "prmem.h"
 
 static PRInt32          gGenerator = 0;
-static TimerThread*     gThread = nsnull;
 
 #ifdef DEBUG_TIMERS
 #include <math.h>
@@ -131,7 +130,7 @@ NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Re
     mCanceled = PR_TRUE;
 
     NS_ASSERTION(gThread, "An armed timer exists after the thread timer stopped.");
-    if (NS_SUCCEEDED(gThread->RemoveTimer(this)))
+    if (NS_SUCCEEDED(gThread->instance->RemoveTimer(this)))
       return 0;
   }
 
@@ -165,22 +164,26 @@ nsTimerImpl::~nsTimerImpl()
   ReleaseCallback();
 }
 
+nsTimerImpl::Root*
+nsTimerImpl::gThread;
+
+nsTimerImpl::Root::Root()
+  : MMgc::GCRoot(NS_GetGC())
+  , instance(new TimerThread())
+{
+}
+
 //static
 nsresult
 nsTimerImpl::Startup()
 {
   nsresult rv;
 
-  gThread = new TimerThread();
-  if (!gThread) return NS_ERROR_OUT_OF_MEMORY;
+  gThread = new Root();
+  if (!gThread || !gThread->instance)
+    return NS_ERROR_OUT_OF_MEMORY;
 
-  NS_ADDREF(gThread);
-  rv = gThread->InitLocks();
-
-  if (NS_FAILED(rv)) {
-    NS_RELEASE(gThread);
-  }
-
+  rv = gThread->instance->InitLocks();
   return rv;
 }
 
@@ -199,8 +202,9 @@ void nsTimerImpl::Shutdown()
   if (!gThread)
     return;
 
-  gThread->Shutdown();
-  NS_RELEASE(gThread);
+  gThread->instance->Shutdown();
+  delete gThread;
+  gThread = nsnull;
 }
 
 
@@ -210,7 +214,7 @@ nsresult nsTimerImpl::InitCommon(PRUint3
 
   NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED);
 
-  rv = gThread->Init();
+  rv = gThread->instance->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   /**
@@ -228,14 +232,14 @@ nsresult nsTimerImpl::InitCommon(PRUint3
    * because RemoveTimer is idempotent.
    */
   if (mArmed)
-    gThread->RemoveTimer(this);
+    gThread->instance->RemoveTimer(this);
   mCanceled = PR_FALSE;
   mGeneration = PR_AtomicIncrement(&gGenerator);
 
   mType = (PRUint8)aType;
   SetDelayInternal(aDelay);
 
-  return gThread->AddTimer(this);
+  return gThread->instance->AddTimer(this);
 }
 
 NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
@@ -262,7 +266,6 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallb
   ReleaseCallback();
   mCallbackType = CALLBACK_TYPE_INTERFACE;
   mCallback.i = aCallback;
-  NS_ADDREF(mCallback.i);
 
   return InitCommon(aType, aDelay);
 }
@@ -276,7 +279,6 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObser
   ReleaseCallback();
   mCallbackType = CALLBACK_TYPE_OBSERVER;
   mCallback.o = aObserver;
-  NS_ADDREF(mCallback.o);
 
   return InitCommon(aType, aDelay);
 }
@@ -286,7 +288,7 @@ NS_IMETHODIMP nsTimerImpl::Cancel()
   mCanceled = PR_TRUE;
 
   if (gThread)
-    gThread->RemoveTimer(this);
+    gThread->instance->RemoveTimer(this);
 
   ReleaseCallback();
 
@@ -303,7 +305,7 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(PRUi
   SetDelayInternal(aDelay);
 
   if (!mFiring && gThread)
-    gThread->TimerDelayChanged(this);
+    gThread->instance->TimerDelayChanged(this);
 
   return NS_OK;
 }
@@ -340,9 +342,9 @@ NS_IMETHODIMP nsTimerImpl::GetCallback(n
 NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback)
 {
   if (mCallbackType == CALLBACK_TYPE_INTERFACE)
-    NS_IF_ADDREF(*aCallback = mCallback.i);
+    *aCallback = mCallback.i;
   else if (mTimerCallbackWhileFiring)
-    NS_ADDREF(*aCallback = mTimerCallbackWhileFiring);
+    *aCallback = mTimerCallbackWhileFiring;
   else
     *aCallback = nsnull;
 
@@ -382,7 +384,7 @@ void nsTimerImpl::Fire()
     timeout -= PR_MillisecondsToInterval(mDelay);
   }
   if (gThread)
-    gThread->UpdateFilter(mDelay, timeout, now);
+    gThread->instance->UpdateFilter(mDelay, timeout, now);
 
   if (mCallbackType == CALLBACK_TYPE_INTERFACE)
     mTimerCallbackWhileFiring = mCallback.i;
@@ -437,7 +439,7 @@ void nsTimerImpl::Fire()
   if (mType == TYPE_REPEATING_SLACK) {
     SetDelayInternal(mDelay); // force mTimeout to be recomputed.
     if (gThread)
-      gThread->AddTimer(this);
+      gThread->instance->AddTimer(this);
   }
 }
 
@@ -471,8 +473,8 @@ private:
 
 NS_IMETHODIMP nsTimerEvent::Run()
 {
-  nsRefPtr<nsTimerImpl> timer;
-  timer.swap(mTimer);
+  nsTimerImpl* timer = nsnull;
+  swap(timer, mTimer);
 
   if (mGeneration != timer->GetGeneration())
     return NS_OK;
@@ -515,7 +517,7 @@ nsresult nsTimerImpl::PostTimerEvent()
   if (mType == TYPE_REPEATING_PRECISE) {
     SetDelayInternal(mDelay);
     if (gThread) {
-      nsresult rv = gThread->AddTimer(this);
+      nsresult rv = gThread->instance->AddTimer(this);
       if (NS_FAILED(rv))
         return rv;
     }
@@ -523,7 +525,7 @@ nsresult nsTimerImpl::PostTimerEvent()
 
   nsresult rv = mCallingThread->Dispatch(event, NS_DISPATCH_NORMAL);
   if (NS_FAILED(rv) && gThread)
-    gThread->RemoveTimer(this);
+    gThread->instance->RemoveTimer(this);
   return rv;
 }
 
@@ -561,7 +563,6 @@ NS_NewTimer(nsITimer* *aResult, nsTimerC
     nsTimerImpl* timer = new nsTimerImpl();
     if (timer == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(timer);
 
     nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure, 
                                               aDelay, aType);
diff --git a/xpcom/threads/nsTimerImpl.h b/xpcom/threads/nsTimerImpl.h
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -83,7 +83,9 @@ enum {
 // Is interval-time t less than u, even if t has wrapped PRIntervalTime?
 #define TIMER_LESS_THAN(t, u)   ((t) - (u) > DELAY_INTERVAL_LIMIT)
 
-class nsTimerImpl : public nsITimer
+class TimerThread;
+
+class nsTimerImpl : public XPCOMGCFinalizedObject, public nsITimer
 {
 public:
 
@@ -104,6 +106,15 @@ public:
   PRInt32 GetGeneration() { return mGeneration; }
 
 private:
+  class Root : public MMgc::GCRoot
+  {
+  public:
+    Root();
+
+    TimerThread* instance;
+  };
+  static Root* gThread;
+
   ~nsTimerImpl();
   nsresult InitCommon(PRUint32 aType, PRUint32 aDelay);