Bug 966384 - Promises on workers use correct busy count. r=khuey, a=sledru
authorNikhil Marathe <nsm.nikhil@gmail.com>
Mon, 17 Feb 2014 12:24:36 +0530
changeset 182894 fbabfaa4ab777a473ab0b2cf6fd385ea2749e173
parent 182893 2ac2e3a81f7b940cb16367376497d6692e2d4c9b
child 182895 1e578a03b49173071b79661207e29ca29a6f2fa8
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, sledru
bugs966384
milestone29.0a2
Bug 966384 - Promises on workers use correct busy count. r=khuey, a=sledru
dom/promise/Promise.cpp
dom/workers/WorkerRunnable.cpp
dom/workers/WorkerRunnable.h
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -52,21 +52,21 @@ public:
     mPromise->RunTask();
     return NS_OK;
   }
 
 private:
   nsRefPtr<Promise> mPromise;
 };
 
-class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable
+class WorkerPromiseTask MOZ_FINAL : public WorkerSameThreadRunnable
 {
 public:
   WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
+    : WorkerSameThreadRunnable(aWorkerPrivate)
     , mPromise(aPromise)
   {
     MOZ_ASSERT(aPromise);
     MOZ_COUNT_CTOR(WorkerPromiseTask);
   }
 
   ~WorkerPromiseTask()
   {
@@ -156,25 +156,25 @@ public:
 
   NS_IMETHOD Run()
   {
     RunInternal();
     return NS_OK;
   }
 };
 
-class WorkerPromiseResolverTask MOZ_FINAL : public WorkerRunnable,
+class WorkerPromiseResolverTask MOZ_FINAL : public WorkerSameThreadRunnable,
                                             public PromiseResolverMixin
 {
 public:
   WorkerPromiseResolverTask(WorkerPrivate* aWorkerPrivate,
                             Promise* aPromise,
                             JS::Handle<JS::Value> aValue,
                             Promise::PromiseState aState)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
+    : WorkerSameThreadRunnable(aWorkerPrivate),
       PromiseResolverMixin(aPromise, aValue, aState)
   {}
 
   ~WorkerPromiseResolverTask()
   {}
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
@@ -827,17 +827,17 @@ Promise::AppendCallbacks(PromiseCallback
   if (mState != Pending && !mTaskPending) {
     if (MOZ_LIKELY(NS_IsMainThread())) {
       nsRefPtr<PromiseTask> task = new PromiseTask(this);
       NS_DispatchToCurrentThread(task);
     } else {
       WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
       MOZ_ASSERT(worker);
       nsRefPtr<WorkerPromiseTask> task = new WorkerPromiseTask(worker, this);
-      worker->Dispatch(task);
+      task->Dispatch(worker->GetJSContext());
     }
     mTaskPending = true;
   }
 }
 
 void
 Promise::RunTask()
 {
@@ -1040,17 +1040,17 @@ Promise::RunResolveTask(JS::Handle<JS::V
       nsRefPtr<PromiseResolverTask> task =
         new PromiseResolverTask(this, aValue, aState);
       NS_DispatchToCurrentThread(task);
     } else {
       WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
       MOZ_ASSERT(worker);
       nsRefPtr<WorkerPromiseResolverTask> task =
         new WorkerPromiseResolverTask(worker, this, aValue, aState);
-      worker->Dispatch(task);
+      task->Dispatch(worker->GetJSContext());
     }
     return;
   }
 
   // Promise.all() or Promise.race() implementations will repeatedly call
   // Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
   // from asserting.
   if (mState != Pending) {
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -2,20 +2,22 @@
 /* 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/. */
 
 #include "WorkerRunnable.h"
 
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+#include "mozilla/DebugOnly.h"
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
-#include "nsThreadUtils.h"
 
 #include "WorkerPrivate.h"
 
 USING_WORKERS_NAMESPACE
 
 namespace {
 
 const nsIID kWorkerRunnableIID = {
@@ -473,8 +475,48 @@ MainThreadWorkerControlRunnable::PostDis
   AssertIsOnMainThread();
 
   if (aCx && !aDispatchResult) {
     JS_ReportPendingException(aCx);
   }
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
+
+bool
+WorkerSameThreadRunnable::PreDispatch(JSContext* aCx,
+                                      WorkerPrivate* aWorkerPrivate)
+{
+  aWorkerPrivate->AssertIsOnWorkerThread();
+  return true;
+}
+
+void
+WorkerSameThreadRunnable::PostDispatch(JSContext* aCx,
+                                       WorkerPrivate* aWorkerPrivate,
+                                       bool aDispatchResult)
+{
+  aWorkerPrivate->AssertIsOnWorkerThread();
+  if (aDispatchResult) {
+    DebugOnly<bool> willIncrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
+    // Should never fail since if this thread is still running, so should the
+    // parent and it should be able to process a control runnable.
+    MOZ_ASSERT(willIncrement);
+  }
+}
+
+void
+WorkerSameThreadRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                                  bool aRunResult)
+{
+  MOZ_ASSERT(aCx);
+  MOZ_ASSERT(aWorkerPrivate);
+
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  DebugOnly<bool> willDecrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false);
+  MOZ_ASSERT(willDecrement);
+
+  if (!aRunResult) {
+    JS_ReportPendingException(aCx);
+  }
+}
+
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -309,11 +309,39 @@ protected:
     return true;
   }
 
   virtual void
   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                bool aDispatchResult) MOZ_OVERRIDE;
 };
 
+// A WorkerRunnable that should be dispatched from the worker to itself for
+// async tasks. This will increment the busy count PostDispatch() (only if
+// dispatch was successful) and decrement it in PostRun().
+//
+// Async tasks will almost always want to use this since
+// a WorkerSameThreadRunnable keeps the Worker from being GCed.
+class WorkerSameThreadRunnable : public WorkerRunnable
+{
+protected:
+  WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
+  : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+  { }
+
+  virtual ~WorkerSameThreadRunnable()
+  { }
+
+  virtual bool
+  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
+
+  virtual void
+  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+               bool aDispatchResult) MOZ_OVERRIDE;
+
+  virtual void
+  PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+          bool aRunResult) MOZ_OVERRIDE;
+};
+
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_workerrunnable_h__