Bug 1121129 - Guard against multiple threads dispatching to a worker thread at the same time, r=khuey.
authorBen Turner <bent.mozilla@gmail.com>
Wed, 14 Jan 2015 13:50:03 -0800
changeset 223855 ca56aea7e10e929fd57c7bf9c66f8307b216d7e0
parent 223854 30cb4f8ad6a50e47c7defb2341b263ab9ebe4ac0
child 223856 9932fb743bf8a04e8b7b10afa70c6d0d72b65725
push id54041
push userbturner@mozilla.com
push dateWed, 14 Jan 2015 21:50:08 +0000
treeherdermozilla-inbound@ca56aea7e10e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1121129
milestone38.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 1121129 - Guard against multiple threads dispatching to a worker thread at the same time, r=khuey.
dom/workers/WorkerThread.cpp
dom/workers/WorkerThread.h
--- a/dom/workers/WorkerThread.cpp
+++ b/dom/workers/WorkerThread.cpp
@@ -63,25 +63,25 @@ private:
 
   NS_DECL_NSITHREADOBSERVER
 };
 
 WorkerThread::WorkerThread()
   : nsThread(nsThread::NOT_MAIN_THREAD, kWorkerStackSize)
   , mWorkerPrivateCondVar(mLock, "WorkerThread::mWorkerPrivateCondVar")
   , mWorkerPrivate(nullptr)
-  , mOtherThreadDispatchingViaEventTarget(false)
+  , mOtherThreadsDispatchingViaEventTarget(0)
   , mAcceptingNonWorkerRunnables(true)
 {
 }
 
 WorkerThread::~WorkerThread()
 {
   MOZ_ASSERT(!mWorkerPrivate);
-  MOZ_ASSERT(!mOtherThreadDispatchingViaEventTarget);
+  MOZ_ASSERT(!mOtherThreadsDispatchingViaEventTarget);
   MOZ_ASSERT(mAcceptingNonWorkerRunnables);
 }
 
 // static
 already_AddRefed<WorkerThread>
 WorkerThread::Create(const WorkerThreadFriendKey& /* aKey */)
 {
   MOZ_ASSERT(nsThreadManager::get());
@@ -118,21 +118,21 @@ WorkerThread::SetWorker(const WorkerThre
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(RemoveObserver(mObserver)));
     mObserver = nullptr;
 
     {
       MutexAutoLock lock(mLock);
 
       MOZ_ASSERT(mWorkerPrivate);
       MOZ_ASSERT(!mAcceptingNonWorkerRunnables);
-      MOZ_ASSERT(!mOtherThreadDispatchingViaEventTarget,
+      MOZ_ASSERT(!mOtherThreadsDispatchingViaEventTarget,
                  "XPCOM Dispatch hapenning at the same time our thread is "
                  "being unset! This should not be possible!");
 
-      while (mOtherThreadDispatchingViaEventTarget) {
+      while (mOtherThreadsDispatchingViaEventTarget) {
         mWorkerPrivateCondVar.Wait();
       }
 
       mAcceptingNonWorkerRunnables = true;
       mWorkerPrivate = nullptr;
     }
   }
 }
@@ -229,24 +229,24 @@ WorkerThread::Dispatch(nsIRunnable* aRun
     // No need to lock here because it is only modified on this thread.
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     workerPrivate = mWorkerPrivate;
   } else {
     MutexAutoLock lock(mLock);
 
-    MOZ_ASSERT(!mOtherThreadDispatchingViaEventTarget);
+    MOZ_ASSERT(mOtherThreadsDispatchingViaEventTarget < UINT32_MAX);
 
     if (mWorkerPrivate) {
       workerPrivate = mWorkerPrivate;
 
-      // Setting this flag will make the worker thread sleep if it somehow tries
-      // to unset mWorkerPrivate while we're using it.
-      mOtherThreadDispatchingViaEventTarget = true;
+      // Incrementing this counter will make the worker thread sleep if it
+      // somehow tries to unset mWorkerPrivate while we're using it.
+      mOtherThreadsDispatchingViaEventTarget++;
     }
   }
 
   nsIRunnable* runnableToDispatch;
   nsRefPtr<WorkerRunnable> workerRunnable;
 
   if (aRunnable && onWorkerThread) {
     workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
@@ -265,20 +265,21 @@ WorkerThread::Dispatch(nsIRunnable* aRun
 
       workerPrivate->mCondVar.Notify();
     }
 
     // Now unset our waiting flag.
     {
       MutexAutoLock lock(mLock);
 
-      MOZ_ASSERT(mOtherThreadDispatchingViaEventTarget);
-      mOtherThreadDispatchingViaEventTarget = false;
+      MOZ_ASSERT(mOtherThreadsDispatchingViaEventTarget);
 
-      mWorkerPrivateCondVar.Notify();
+      if (!--mOtherThreadsDispatchingViaEventTarget) {
+        mWorkerPrivateCondVar.Notify();
+      }
     }
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
--- a/dom/workers/WorkerThread.h
+++ b/dom/workers/WorkerThread.h
@@ -47,17 +47,17 @@ class WorkerThread MOZ_FINAL
 
   // Protected by nsThread::mLock.
   WorkerPrivate* mWorkerPrivate;
 
   // Only touched on the target thread.
   nsRefPtr<Observer> mObserver;
 
   // Protected by nsThread::mLock and waited on with mWorkerPrivateCondVar.
-  bool mOtherThreadDispatchingViaEventTarget;
+  uint32_t mOtherThreadsDispatchingViaEventTarget;
 
   // Protected by nsThread::mLock.
   DebugOnly<bool> mAcceptingNonWorkerRunnables;
 
 public:
   static already_AddRefed<WorkerThread>
   Create(const WorkerThreadFriendKey& aKey);