Bug 1121129 - Guard against multiple threads dispatching to a worker thread at the same time. r=khuey, a=lmandel
authorBen Turner <bent.mozilla@gmail.com>
Wed, 14 Jan 2015 13:50:03 -0800
changeset 249317 dab26db33addd50a75063660568c84ac7e280242
parent 249316 c64b0256416eb04cb66219ff39e5fd7d47482c19
child 249318 81d32b8782721f002d0749a24a858b75ed854823
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, lmandel
bugs1121129
milestone37.0a2
Bug 1121129 - Guard against multiple threads dispatching to a worker thread at the same time. r=khuey, a=lmandel
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);