Bug 1418074 - Introducing a WorkerHolder to release AbortSignal on the correct thread, r=bkelly a=gchang
☠☠ backed out by 1b3d0019f65e ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 22 Dec 2017 10:06:47 +0100
changeset 445563 9875bb519e72d8cf45ca75ca494c8bb51447749b
parent 445562 2327b280b3fceb883ec2120f3635b2f099bda300
child 445564 7640a0204f44274514f7bc833cf9e17ac02c2b92
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly, gchang
bugs1418074
milestone58.0
Bug 1418074 - Introducing a WorkerHolder to release AbortSignal on the correct thread, r=bkelly a=gchang
dom/fetch/Fetch.cpp
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -157,24 +157,41 @@ private:
   ~AbortSignalProxy()
   {
     NS_ProxyRelease(
       "AbortSignalProxy::mSignalMainThread",
       mMainThreadEventTarget, mSignalMainThread.forget());
   }
 };
 
+class WorkerFetchResolver;
+
+class WorkerNotifier final : public WorkerHolder
+{
+  RefPtr<WorkerFetchResolver> mResolver;
+
+public:
+  explicit WorkerNotifier(WorkerFetchResolver* aResolver)
+    : WorkerHolder("WorkerNotifier", AllowIdleShutdownStart)
+    , mResolver(aResolver)
+  {}
+
+  bool
+  Notify(Status aStatus) override;
+};
+
 class WorkerFetchResolver final : public FetchDriverObserver
 {
   // Thread-safe:
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
   RefPtr<AbortSignalProxy> mSignalProxy;
 
   // Touched only on the worker thread.
   RefPtr<FetchObserver> mFetchObserver;
+  UniquePtr<WorkerHolder> mWorkerHolder;
 
 public:
   // Returns null if worker is shutting down.
   static already_AddRefed<WorkerFetchResolver>
   Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise,
          AbortSignal* aSignal, FetchObserver* aObserver)
   {
     MOZ_ASSERT(aWorkerPrivate);
@@ -188,16 +205,21 @@ public:
     RefPtr<AbortSignalProxy> signalProxy;
     if (aSignal) {
       signalProxy =
         new AbortSignalProxy(aSignal, aWorkerPrivate->MainThreadEventTarget());
     }
 
     RefPtr<WorkerFetchResolver> r =
       new WorkerFetchResolver(proxy, signalProxy, aObserver);
+
+    if (NS_WARN_IF(!r->HoldWorker(aWorkerPrivate))) {
+      return nullptr;
+    }
+
     return r.forget();
   }
 
   AbortSignal*
   GetAbortSignalForMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
@@ -266,16 +288,18 @@ public:
     mPromiseProxy->CleanUp();
 
     mFetchObserver = nullptr;
 
     if (mSignalProxy) {
       mSignalProxy->Shutdown();
       mSignalProxy = nullptr;
     }
+
+    mWorkerHolder = nullptr;
   }
 
 private:
    WorkerFetchResolver(PromiseWorkerProxy* aProxy,
                        AbortSignalProxy* aSignalProxy,
                        FetchObserver* aObserver)
     : mPromiseProxy(aProxy)
     , mSignalProxy(aSignalProxy)
@@ -285,16 +309,28 @@ private:
     MOZ_ASSERT(mPromiseProxy);
   }
 
   ~WorkerFetchResolver()
   {}
 
   virtual void
   FlushConsoleReport() override;
+
+  bool
+  HoldWorker(WorkerPrivate* aWorkerPrivate)
+  {
+    UniquePtr<WorkerNotifier> wn(new WorkerNotifier(this));
+    if (NS_WARN_IF(!wn->HoldWorker(aWorkerPrivate, Canceling))) {
+      return false;
+    }
+
+    mWorkerHolder = Move(wn);
+    return true;
+  }
 };
 
 class MainThreadFetchResolver final : public FetchDriverObserver
 {
   RefPtr<Promise> mPromise;
   RefPtr<Response> mResponse;
   RefPtr<FetchObserver> mFetchObserver;
   RefPtr<AbortSignal> mSignal;
@@ -719,16 +755,28 @@ public:
   {
     WorkerRunInternal(aWorkerPrivate);
     return true;
   }
 
   // Control runnable cancel already calls Run().
 };
 
+bool
+WorkerNotifier::Notify(Status aStatus)
+{
+  if (mResolver) {
+    // This will nullify this object.
+    // No additional operation after this line!
+    mResolver->Shutdown(mWorkerPrivate);
+  }
+
+  return true;
+}
+
 void
 WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
 {
   AssertIsOnMainThread();
 
   MutexAutoLock lock(mPromiseProxy->Lock());
   if (mPromiseProxy->CleanedUp()) {
     return;