Bug 1319278 P1 Add a WorkerControlEventTarget that executes runnables as WorkerControlRunnables. r=baku
authorBen Kelly <ben@wanderview.com>
Thu, 26 Jan 2017 08:01:32 -0800
changeset 377893 6e1f8f0c4d940ebdd5a6b8186214275115a5b8e4
parent 377892 668f68822c19b8370fe353c5a3da44838cfe1f59
child 377894 e20b4c55bd6a50b026b40ba5438b0fd0d6cae6a8
push id7198
push userjlorenzo@mozilla.com
push dateTue, 18 Apr 2017 12:07:49 +0000
treeherdermozilla-beta@d57aa49c3948 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1319278
milestone54.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 1319278 P1 Add a WorkerControlEventTarget that executes runnables as WorkerControlRunnables. r=baku
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1604,16 +1604,148 @@ TimerThreadEventTarget::IsOnCurrentThrea
     return rv;
   }
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(TimerThreadEventTarget, nsIEventTarget)
 
+namespace {
+
+class WrappedControlRunnable final : public WorkerControlRunnable
+{
+  nsCOMPtr<nsIRunnable> mInner;
+
+  ~WrappedControlRunnable()
+  {
+  }
+
+public:
+  WrappedControlRunnable(WorkerPrivate* aWorkerPrivate,
+                         already_AddRefed<nsIRunnable>&& aInner)
+    : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
+    , mInner(aInner)
+  {
+  }
+
+  virtual bool
+  PreDispatch(WorkerPrivate* aWorkerPrivate) override
+  {
+    // Silence bad assertions, this can be dispatched from any thread.
+    return true;
+  }
+
+  virtual void
+  PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+  {
+    // Silence bad assertions, this can be dispatched from any thread.
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    mInner->Run();
+    return true;
+  }
+
+  nsresult
+  Cancel() override
+  {
+    // First run the default cancelation code
+    WorkerControlRunnable::Cancel();
+
+    // Attempt to cancel the inner runnable as well
+    nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner);
+    if (cr) {
+      return cr->Cancel();
+    }
+    return NS_OK;
+  }
+};
+
+} // anonymous namespace
+
+BEGIN_WORKERS_NAMESPACE
+
+class WorkerControlEventTarget final : public nsIEventTarget
+{
+  mozilla::Mutex mMutex;
+  WorkerPrivate* mWorkerPrivate;
+
+  ~WorkerControlEventTarget() = default;
+
+public:
+  explicit WorkerControlEventTarget(WorkerPrivate* aWorkerPrivate)
+    : mMutex("WorkerControlEventTarget")
+    , mWorkerPrivate(aWorkerPrivate)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate);
+  }
+
+  void
+  ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate)
+  {
+    MutexAutoLock lock(mMutex);
+    MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate == aWorkerPrivate);
+    mWorkerPrivate = nullptr;
+  }
+
+  NS_IMETHOD
+  DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override
+  {
+    nsCOMPtr<nsIRunnable> runnable(aRunnable);
+    return Dispatch(runnable.forget(), aFlags);
+  }
+
+  NS_IMETHOD
+  Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override
+  {
+    MutexAutoLock lock(mMutex);
+
+    if (!mWorkerPrivate) {
+      return NS_ERROR_FAILURE;
+    }
+
+    RefPtr<WorkerControlRunnable> r = new WrappedControlRunnable(mWorkerPrivate,
+                                                                 Move(aRunnable));
+    if (!r->Dispatch()) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  NS_IMETHOD
+  IsOnCurrentThread(bool* aIsOnCurrentThread) override
+  {
+    MOZ_ASSERT(aIsOnCurrentThread);
+    MutexAutoLock lock(mMutex);
+
+    if (!mWorkerPrivate) {
+      *aIsOnCurrentThread = false;
+      return NS_OK;
+    }
+
+    return mWorkerPrivate->IsOnCurrentThread(aIsOnCurrentThread);
+  }
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+};
+
+NS_IMPL_ISUPPORTS(WorkerControlEventTarget, nsIEventTarget)
+
+END_WORKERS_NAMESPACE
+
 WorkerLoadInfo::WorkerLoadInfo()
   : mLoadFlags(nsIRequest::LOAD_NORMAL)
   , mWindowID(UINT64_MAX)
   , mServiceWorkerID(0)
   , mReferrerPolicy(net::RP_Unset)
   , mFromWindow(false)
   , mEvalAllowed(false)
   , mReportCSPViolations(false)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -80,16 +80,17 @@ struct PRThread;
 class ReportDebuggerErrorRunnable;
 class PostDebuggerMessageRunnable;
 
 BEGIN_WORKERS_NAMESPACE
 
 class AutoSyncLoopHolder;
 class SharedWorker;
 class ServiceWorkerClientInfo;
+class WorkerControlEventTarget;
 class WorkerControlRunnable;
 class WorkerDebugger;
 class WorkerPrivate;
 class WorkerRunnable;
 class WorkerThread;
 
 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
 // object. It exists to avoid changing a lot of code to use Mutex* instead of