Bug 1362444 P1 Allow idle worker shutdown to begin for an opt-in WorkerHolder mode. r=baku
authorBen Kelly <ben@wanderview.com>
Wed, 10 May 2017 09:27:10 -0700
changeset 408045 179023a3c485f01838b7f5446bc2ef9adf89bcfb
parent 408044 36496a0fbbab4f9fe0765301cec818233831b23a
child 408046 4dfa701c548971d35cd2831e0c1a7b2f6c1e6478
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1362444
milestone55.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 1362444 P1 Allow idle worker shutdown to begin for an opt-in WorkerHolder mode. r=baku
dom/workers/WorkerHolder.cpp
dom/workers/WorkerHolder.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/workers/WorkerHolder.cpp
+++ b/dom/workers/WorkerHolder.cpp
@@ -4,18 +4,19 @@
  * 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 "WorkerHolder.h"
 #include "WorkerPrivate.h"
 
 BEGIN_WORKERS_NAMESPACE
 
-WorkerHolder::WorkerHolder()
+WorkerHolder::WorkerHolder(Behavior aBehavior)
   : mWorkerPrivate(nullptr)
+  , mBehavior(aBehavior)
 {
 }
 
 WorkerHolder::~WorkerHolder()
 {
   NS_ASSERT_OWNINGTHREAD(WorkerHolder);
   ReleaseWorkerInternal();
   MOZ_ASSERT(mWorkerPrivate == nullptr);
@@ -40,16 +41,22 @@ void
 WorkerHolder::ReleaseWorker()
 {
   NS_ASSERT_OWNINGTHREAD(WorkerHolder);
   MOZ_ASSERT(mWorkerPrivate);
 
   ReleaseWorkerInternal();
 }
 
+WorkerHolder::Behavior
+WorkerHolder::GetBehavior() const
+{
+  return mBehavior;
+}
+
 void
 WorkerHolder::ReleaseWorkerInternal()
 {
   NS_ASSERT_OWNINGTHREAD(WorkerHolder);
 
   if (mWorkerPrivate) {
     mWorkerPrivate->AssertIsOnWorkerThread();
     mWorkerPrivate->RemoveHolder(this);
--- a/dom/workers/WorkerHolder.h
+++ b/dom/workers/WorkerHolder.h
@@ -69,28 +69,37 @@ enum Status
   Dead
 };
 
 class WorkerHolder
 {
 public:
   NS_DECL_OWNINGTHREAD
 
-  WorkerHolder();
+  enum Behavior {
+    AllowIdleShutdownStart,
+    PreventIdleShutdownStart,
+  };
+
+  explicit WorkerHolder(Behavior aBehavior = PreventIdleShutdownStart);
   virtual ~WorkerHolder();
 
   bool HoldWorker(WorkerPrivate* aWorkerPrivate, Status aFailStatus);
   void ReleaseWorker();
 
   virtual bool Notify(Status aStatus) = 0;
 
+  Behavior GetBehavior() const;
+
 protected:
   void ReleaseWorkerInternal();
 
   WorkerPrivate* MOZ_NON_OWNING_REF mWorkerPrivate;
 
 private:
   void AssertIsOwningThread() const;
+
+  const Behavior mBehavior;
 };
 
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_WorkerHolder_h */
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4424,16 +4424,17 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
                              WorkerLoadInfo& aLoadInfo)
   : WorkerPrivateParent<WorkerPrivate>(aParent, aScriptURL,
                                        aIsChromeWorker, aWorkerType,
                                        aWorkerName, aLoadInfo)
   , mDebuggerRegistered(false)
   , mDebugger(nullptr)
   , mJSContext(nullptr)
   , mPRThread(nullptr)
+  , mNumHoldersPreventingShutdownStart(0)
   , mDebuggerEventLoopLevel(0)
   , mMainThreadEventTarget(do_GetMainThread())
   , mWorkerControlEventTarget(new WorkerControlEventTarget(this))
   , mErrorHandlerRecursionCount(0)
   , mNextTimeoutId(1)
   , mStatus(Pending)
   , mFrozen(false)
   , mTimerRunning(false)
@@ -5642,34 +5643,40 @@ WorkerPrivate::AddHolder(WorkerHolder* a
 
     if (mStatus >= aFailStatus) {
       return false;
     }
   }
 
   MOZ_ASSERT(!mHolders.Contains(aHolder), "Already know about this one!");
 
-  if (mHolders.IsEmpty() && !ModifyBusyCountFromWorker(true)) {
-    return false;
+  if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) {
+    if (!mNumHoldersPreventingShutdownStart && !ModifyBusyCountFromWorker(true)) {
+      return false;
+    }
+    mNumHoldersPreventingShutdownStart += 1;
   }
 
   mHolders.AppendElement(aHolder);
   return true;
 }
 
 void
 WorkerPrivate::RemoveHolder(WorkerHolder* aHolder)
 {
   AssertIsOnWorkerThread();
 
   MOZ_ASSERT(mHolders.Contains(aHolder), "Didn't know about this one!");
   mHolders.RemoveElement(aHolder);
 
-  if (mHolders.IsEmpty() && !ModifyBusyCountFromWorker(false)) {
-    NS_WARNING("Failed to modify busy count!");
+  if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) {
+    mNumHoldersPreventingShutdownStart -= 1;
+    if (!mNumHoldersPreventingShutdownStart && !ModifyBusyCountFromWorker(false)) {
+      NS_WARNING("Failed to modify busy count!");
+    }
   }
 }
 
 void
 WorkerPrivate::NotifyHolders(JSContext* aCx, Status aStatus)
 {
   AssertIsOnWorkerThread();
   MOZ_ASSERT(!JS_IsExceptionPending(aCx));
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -991,16 +991,17 @@ class WorkerPrivate : public WorkerPriva
   RefPtr<WorkerThread> mThread;
   PRThread* mPRThread;
 
   // Things touched on worker thread only.
   RefPtr<WorkerGlobalScope> mScope;
   RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
   nsTArray<ParentType*> mChildWorkers;
   nsTObserverArray<WorkerHolder*> mHolders;
+  uint32_t mNumHoldersPreventingShutdownStart;
   nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
   uint32_t mDebuggerEventLoopLevel;
   RefPtr<ThrottledEventQueue> mMainThreadThrottledEventQueue;
   nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
   RefPtr<WorkerControlEventTarget> mWorkerControlEventTarget;
 
   struct SyncLoopInfo
   {