Bug 1300659 P4 Use ThrottledEventQueue in workers. r=baku
authorBen Kelly <ben@wanderview.com>
Mon, 07 Nov 2016 12:30:17 -0800
changeset 348267 2ff33f3c59d5782f460d03d28f91a0a2dce0b8f0
parent 348266 00efae73e570689a72761918362c2e0e1e819183
child 348268 24d97dc514d4b8fe608e9aee7527615c1e613606
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1300659
milestone52.0a1
Bug 1300659 P4 Use ThrottledEventQueue in workers. r=baku
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerRunnable.cpp
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Likely.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/Move.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Console.h"
+#include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/ExtendableMessageEventBinding.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
@@ -65,17 +66,17 @@
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/TaskQueue.h"
+#include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsError.h"
 #include "nsDOMJSUtils.h"
 #include "nsHostObjectProtocolHandler.h"
@@ -4117,36 +4118,48 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
   else {
     AssertIsOnMainThread();
     RuntimeService::GetDefaultPreferences(mPreferences);
     mOnLine = !NS_IsOffline();
   }
 
   nsCOMPtr<nsIEventTarget> target;
 
+  // A child worker just inherits the parent workers ThrottledEventQueue
+  // and main thread target for now.  This is mainly due to the restriction
+  // that ThrottledEventQueue can only be created on the main thread at the
+  // moment.
   if (aParent) {
-    target = aParent->MainThreadEventTarget();
-  }
-
-  // TODO: If we have a window, try to use its MainThreadTaskQueue as the
-  //       target for our sub-queue.
+    mMainThreadThrottledEventQueue = aParent->mMainThreadThrottledEventQueue;
+    mMainThreadEventTarget = aParent->mMainThreadEventTarget;
+    return;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+  target = GetWindow() ? GetWindow()->GetThrottledEventQueue() : nullptr;
 
   if (!target) {
     nsCOMPtr<nsIThread> mainThread;
     NS_GetMainThread(getter_AddRefs(mainThread));
     MOZ_DIAGNOSTIC_ASSERT(mainThread);
     target = mainThread;
   }
 
-  // Throttle events to the main thread using a TaskQueue specific to this
-  // worker thread.
-  mMainThreadTaskQueue = new TaskQueue(target.forget());
-
-  // Expose our task queue as the worker's main thread nsIEventTarget.
-  mMainThreadEventTarget = mMainThreadTaskQueue->WrapAsEventTarget();
+  // Throttle events to the main thread using a ThrottledEventQueue specific to
+  // this worker thread.  This may return nullptr during shutdown.
+  mMainThreadThrottledEventQueue = ThrottledEventQueue::Create(target);
+
+  // If we were able to creat the throttled event queue, then use it for
+  // dispatching our main thread runnables.  Otherwise use our underlying
+  // base target.
+  if (mMainThreadThrottledEventQueue) {
+    mMainThreadEventTarget = mMainThreadThrottledEventQueue;
+  } else {
+    mMainThreadEventTarget = target.forget();
+  }
 }
 
 WorkerPrivate::~WorkerPrivate()
 {
 }
 
 // static
 already_AddRefed<WorkerPrivate>
@@ -4676,24 +4689,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
 
         {
           MutexAutoLock lock(mMutex);
 
           mStatus = Dead;
           mJSContext = nullptr;
         }
 
-        // Shutdown the main thread TaskQueue and wait for it to drain.  Make
-        // sure to clear our references first, however, so that new runnables
-        // are not dispatched into the closing TaskQueue.
-        mMainThreadEventTarget = do_GetMainThread();
-        RefPtr<TaskQueue> taskQueue = mMainThreadTaskQueue.forget();
-        taskQueue->BeginShutdown();
-        taskQueue->AwaitShutdownAndIdle();
-
         // After mStatus is set to Dead there can be no more
         // WorkerControlRunnables so no need to lock here.
         if (!mControlQueue.IsEmpty()) {
           WorkerControlRunnable* runnable;
           while (mControlQueue.Pop(runnable)) {
             runnable->Cancel();
             runnable->Release();
           }
@@ -4753,19 +4758,19 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
       // Both the debugger event queue and the normal event queue has been
       // exhausted, cancel the periodic GC timer and schedule the idle GC timer.
       SetGCTimerMode(IdleTimer);
     }
 
     // If the worker thread is spamming the main thread faster than it can
     // process the work, then pause the worker thread until the MT catches
     // up.
-    if (mMainThreadTaskQueue &&
-        mMainThreadTaskQueue->ImpreciseLengthForHeuristics() > 5000) {
-      mMainThreadTaskQueue->AwaitIdle();
+    if (mMainThreadThrottledEventQueue &&
+        mMainThreadThrottledEventQueue->Length() > 5000) {
+      mMainThreadThrottledEventQueue->AwaitIdle();
     }
   }
 
   MOZ_CRASH("Shouldn't get here!");
 }
 
 void
 WorkerPrivate::OnProcessNextEvent()
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -55,17 +55,17 @@ class nsITimer;
 class nsIURI;
 template<class T> class nsMainThreadPtrHandle;
 
 namespace JS {
 struct RuntimeStats;
 } // namespace JS
 
 namespace mozilla {
-class TaskQueue;
+class ThrottledEventQueue;
 namespace dom {
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PromiseNativeHandler;
 class StructuredCloneHolder;
 class WorkerDebuggerGlobalScope;
 class WorkerGlobalScope;
@@ -937,17 +937,17 @@ class WorkerPrivate : public WorkerPriva
 
   // Things touched on worker thread only.
   RefPtr<WorkerGlobalScope> mScope;
   RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
   nsTArray<ParentType*> mChildWorkers;
   nsTObserverArray<WorkerHolder*> mHolders;
   nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
   uint32_t mDebuggerEventLoopLevel;
-  RefPtr<TaskQueue> mMainThreadTaskQueue;
+  RefPtr<ThrottledEventQueue> mMainThreadThrottledEventQueue;
   nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
 
   struct SyncLoopInfo
   {
     explicit SyncLoopInfo(EventTarget* aEventTarget);
 
     RefPtr<EventTarget> mEventTarget;
     bool mCompleted;
@@ -1364,17 +1364,17 @@ public:
     return mWorkerScriptExecutedSuccessfully;
   }
 
   void
   MaybeDispatchLoadFailedRunnable();
 
   // Get the event target to use when dispatching to the main thread
   // from this Worker thread.  This may be the main thread itself or
-  // a TaskQueue throttling runnables to the main thread.
+  // a ThrottledEventQueue to the main thread.
   nsIEventTarget*
   MainThreadEventTarget();
 
   nsresult
   DispatchToMainThread(nsIRunnable* aRunnable,
                        uint32_t aFlags = NS_DISPATCH_NORMAL);
 
   nsresult
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -10,17 +10,16 @@
 #include "nsIEventTarget.h"
 #include "nsIGlobalObject.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/TaskQueue.h"
 #include "mozilla/Telemetry.h"
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerScope.h"