Bug 1052740 - Cancel LazyIdleThread timer before shutting down its thread, r=bsmedberg.
authorBen Turner <bent.mozilla@gmail.com>
Fri, 29 Aug 2014 11:23:31 -0700
changeset 224136 6a6b450605c5268397f712d686815f48be46f5e5
parent 224135 b88f451d3ecc23458b45db408d94bdd9032e84de
child 224137 88b588fb20399e049ee4f15441df31f93bbd98ff
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs1052740
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1052740 - Cancel LazyIdleThread timer before shutting down its thread, r=bsmedberg.
xpcom/threads/LazyIdleThread.cpp
--- a/xpcom/threads/LazyIdleThread.cpp
+++ b/xpcom/threads/LazyIdleThread.cpp
@@ -224,39 +224,53 @@ LazyIdleThread::ScheduleTimer()
     MutexAutoLock lock(mMutex);
 
     MOZ_ASSERT(mIdleNotificationCount, "Should have at least one!");
     --mIdleNotificationCount;
 
     shouldSchedule = !mIdleNotificationCount && !mPendingEventCount;
   }
 
-  if (NS_FAILED(mIdleTimer->Cancel())) {
-    NS_WARNING("Failed to cancel timer!");
-  }
+  if (mIdleTimer) {
+    if (NS_FAILED(mIdleTimer->Cancel())) {
+      NS_WARNING("Failed to cancel timer!");
+    }
 
-  if (shouldSchedule &&
-      NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS,
-                                             nsITimer::TYPE_ONE_SHOT))) {
-    NS_WARNING("Failed to schedule timer!");
+    if (shouldSchedule &&
+        NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS,
+                                               nsITimer::TYPE_ONE_SHOT))) {
+      NS_WARNING("Failed to schedule timer!");
+    }
   }
 }
 
 nsresult
 LazyIdleThread::ShutdownThread()
 {
   ASSERT_OWNING_THREAD();
 
   // Before calling Shutdown() on the real thread we need to put a queue in
   // place in case a runnable is posted to the thread while it's in the
   // process of shutting down. This will be our queue.
   nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queuedRunnables;
 
   nsresult rv;
 
+  // Make sure to cancel the shutdown timer before spinning the event loop
+  // during |mThread->Shutdown()| below. Otherwise the timer might fire and we
+  // could reenter here.
+  if (mIdleTimer) {
+    rv = mIdleTimer->Cancel();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    mIdleTimer = nullptr;
+  }
+
   if (mThread) {
     if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       NS_WARN_IF_FALSE(obs, "Failed to get observer service!");
 
       if (obs &&
           NS_FAILED(obs->RemoveObserver(this, "xpcom-shutdown-threads"))) {
@@ -306,25 +320,16 @@ LazyIdleThread::ShutdownThread()
 
       MOZ_ASSERT(!mPendingEventCount, "Huh?!");
       MOZ_ASSERT(!mIdleNotificationCount, "Huh?!");
       MOZ_ASSERT(mThreadIsShuttingDown, "Huh?!");
       mThreadIsShuttingDown = false;
     }
   }
 
-  if (mIdleTimer) {
-    rv = mIdleTimer->Cancel();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    mIdleTimer = nullptr;
-  }
-
   // If our temporary queue has any runnables then we need to dispatch them.
   if (queuedRunnables.Length()) {
     // If the thread manager has gone away then these runnables will never run.
     if (mShutdown) {
       NS_ERROR("Runnables dispatched to LazyIdleThread will never run!");
       return NS_OK;
     }