Bug 1269963. Part 1 - Add a SyncRunnable::DispatchToThread() overload for AbstractThread. r=bobbyholley.
authorJW Wang <jwwang@mozilla.com>
Wed, 04 May 2016 16:24:25 +0800
changeset 337358 87607f70a502452edfa6f40787e38dcd98bd7e0b
parent 337357 55fb703a89e57bbf1972e6363124936b50f10dc4
child 337359 95e5e81a23509c062bc5b4804bd9662ca25e1d14
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobbyholley
bugs1269963
milestone49.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 1269963. Part 1 - Add a SyncRunnable::DispatchToThread() overload for AbstractThread. r=bobbyholley. MozReview-Commit-ID: Jog4glNrUHw
xpcom/threads/AbstractThread.cpp
xpcom/threads/AbstractThread.h
xpcom/threads/SyncRunnable.h
--- a/xpcom/threads/AbstractThread.cpp
+++ b/xpcom/threads/AbstractThread.cpp
@@ -100,21 +100,29 @@ public:
 private:
   RefPtr<nsIThread> mTarget;
   Maybe<AutoTaskDispatcher> mTailDispatcher;
 };
 
 bool
 AbstractThread::RequiresTailDispatch(AbstractThread* aThread) const
 {
+  MOZ_ASSERT(aThread);
   // We require tail dispatch if both the source and destination
   // threads support it.
   return SupportsTailDispatch() && aThread->SupportsTailDispatch();
 }
 
+bool
+AbstractThread::RequiresTailDispatchFromCurrentThread() const
+{
+  AbstractThread* current = GetCurrent();
+  return current && RequiresTailDispatch(current);
+}
+
 AbstractThread*
 AbstractThread::MainThread()
 {
   MOZ_ASSERT(sMainThread);
   return sMainThread;
 }
 
 void
--- a/xpcom/threads/AbstractThread.h
+++ b/xpcom/threads/AbstractThread.h
@@ -67,16 +67,17 @@ public:
   virtual TaskDispatcher& TailDispatcher() = 0;
 
   // Returns true if this supports the tail dispatcher.
   bool SupportsTailDispatch() const { return mSupportsTailDispatch; }
 
   // Returns true if this thread requires all dispatches originating from
   // aThread go through the tail dispatcher.
   bool RequiresTailDispatch(AbstractThread* aThread) const;
+  bool RequiresTailDispatchFromCurrentThread() const;
 
   virtual TaskQueue* AsTaskQueue() { MOZ_CRASH("Not a task queue!"); }
   virtual nsIThread* AsXPCOMThread() { MOZ_CRASH("Not an XPCOM thread!"); }
 
   // Convenience method for getting an AbstractThread for the main thread.
   static AbstractThread* MainThread();
 
   // Must be called exactly once during startup.
--- a/xpcom/threads/SyncRunnable.h
+++ b/xpcom/threads/SyncRunnable.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_SyncRunnable_h
 #define mozilla_SyncRunnable_h
 
 #include "nsThreadUtils.h"
+#include "mozilla/AbstractThread.h"
 #include "mozilla/Monitor.h"
 
 namespace mozilla {
 
 /**
  * This class will wrap a nsIRunnable and dispatch it to the main thread
  * synchronously. This is different from nsIEventTarget.DISPATCH_SYNC:
  * this class does not spin the event loop waiting for the event to be
@@ -56,24 +57,50 @@ public:
     if (NS_SUCCEEDED(rv)) {
       mozilla::MonitorAutoLock lock(mMonitor);
       while (!mDone) {
         lock.Wait();
       }
     }
   }
 
+  void DispatchToThread(AbstractThread* aThread, bool aForceDispatch = false)
+  {
+    if (!aForceDispatch && aThread->IsCurrentThreadIn()) {
+      mRunnable->Run();
+      return;
+    }
+
+    // Check we don't have tail dispatching here. Otherwise we will deadlock
+    // ourself when spinning the loop below.
+    MOZ_ASSERT(!aThread->RequiresTailDispatchFromCurrentThread());
+
+    aThread->Dispatch(RefPtr<nsIRunnable>(this).forget());
+    mozilla::MonitorAutoLock lock(mMonitor);
+    while (!mDone) {
+      lock.Wait();
+    }
+  }
+
   static void DispatchToThread(nsIEventTarget* aThread,
                                nsIRunnable* aRunnable,
                                bool aForceDispatch = false)
   {
     RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
     s->DispatchToThread(aThread, aForceDispatch);
   }
 
+  static void DispatchToThread(AbstractThread* aThread,
+                               nsIRunnable* aRunnable,
+                               bool aForceDispatch = false)
+  {
+    RefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
+    s->DispatchToThread(aThread, aForceDispatch);
+  }
+
 protected:
   NS_IMETHODIMP Run()
   {
     mRunnable->Run();
 
     mozilla::MonitorAutoLock lock(mMonitor);
     MOZ_ASSERT(!mDone);