Bug 1511749 - Fix a race condition in SharedWorker shutdown, r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 14 Mar 2019 17:42:50 +0000
changeset 524912 45024ae5b1b7a079cfa1913b63dd15c7ba050d87
parent 524911 88f1641459184352c5bf333ef12aa7ac4c3a28e4
child 524913 a0c8d47ee188ee72fb0896dd80b02076f9bcafb5
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1511749
milestone67.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 1511749 - Fix a race condition in SharedWorker shutdown, r=asuth Differential Revision: https://phabricator.services.mozilla.com/D23188
dom/workers/sharedworkers/SharedWorkerManager.cpp
dom/workers/sharedworkers/SharedWorkerManager.h
dom/workers/sharedworkers/SharedWorkerParent.cpp
dom/workers/sharedworkers/SharedWorkerParent.h
dom/workers/sharedworkers/SharedWorkerService.cpp
dom/workers/sharedworkers/SharedWorkerService.h
--- a/dom/workers/sharedworkers/SharedWorkerManager.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp
@@ -14,16 +14,30 @@
 #include "nsIConsoleReportCollector.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPrincipal.h"
 #include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
+// static
+already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
+    SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
+    const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<SharedWorkerManager> manager = new SharedWorkerManager(
+      aPBackgroundEventTarget, aData, aLoadingPrincipal);
+
+  RefPtr<SharedWorkerManagerHolder> holder =
+      new SharedWorkerManagerHolder(manager, aService);
+  return holder.forget();
+}
+
 SharedWorkerManager::SharedWorkerManager(
     nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
     nsIPrincipal* aLoadingPrincipal)
     : mPBackgroundEventTarget(aPBackgroundEventTarget),
       mLoadingPrincipal(aLoadingPrincipal),
       mDomain(aData.domain()),
       mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
       mName(aData.name()),
@@ -60,30 +74,41 @@ bool SharedWorkerManager::MaybeCreateRem
   if (aWindowID) {
     mRemoteWorkerController->AddWindowID(aWindowID);
   }
 
   mRemoteWorkerController->AddPortIdentifier(aPortIdentifier);
   return true;
 }
 
-bool SharedWorkerManager::MatchOnMainThread(
-    const nsACString& aDomain, nsIURI* aScriptURL, const nsAString& aName,
-    nsIPrincipal* aLoadingPrincipal) const {
+already_AddRefed<SharedWorkerManagerHolder>
+SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
+                                       const nsACString& aDomain,
+                                       nsIURI* aScriptURL,
+                                       const nsAString& aName,
+                                       nsIPrincipal* aLoadingPrincipal) {
   MOZ_ASSERT(NS_IsMainThread());
+
   bool urlEquals;
   if (NS_FAILED(aScriptURL->Equals(mResolvedScriptURL, &urlEquals))) {
-    return false;
+    return nullptr;
   }
 
-  return aDomain == mDomain && urlEquals && aName == mName &&
-         // We want to be sure that the window's principal subsumes the
-         // SharedWorker's loading principal and vice versa.
-         mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
-         aLoadingPrincipal->Subsumes(mLoadingPrincipal);
+  bool match = aDomain == mDomain && urlEquals && aName == mName &&
+               // We want to be sure that the window's principal subsumes the
+               // SharedWorker's loading principal and vice versa.
+               mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
+               aLoadingPrincipal->Subsumes(mLoadingPrincipal);
+  if (!match) {
+    return nullptr;
+  }
+
+  RefPtr<SharedWorkerManagerHolder> holder =
+      new SharedWorkerManagerHolder(this, aService);
+  return holder.forget();
 }
 
 void SharedWorkerManager::AddActor(SharedWorkerParent* aParent) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(!mActors.Contains(aParent));
 
   mActors.AppendElement(aParent);
@@ -107,24 +132,25 @@ void SharedWorkerManager::RemoveActor(Sh
   mActors.RemoveElement(aParent);
 
   if (!mActors.IsEmpty()) {
     // Our remaining actors could be all suspended or frozen.
     UpdateSuspend();
     UpdateFrozen();
     return;
   }
+}
 
-  // Time to go.
+void SharedWorkerManager::Terminate() {
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mActors.IsEmpty());
+  MOZ_ASSERT(mHolders.IsEmpty());
 
   mRemoteWorkerController->Terminate();
   mRemoteWorkerController = nullptr;
-
-  // SharedWorkerService exists because it is kept alive by SharedWorkerParent.
-  SharedWorkerService::Get()->RemoveWorkerManager(this);
 }
 
 void SharedWorkerManager::UpdateSuspend() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mRemoteWorkerController);
 
   uint32_t suspended = 0;
 
@@ -204,10 +230,67 @@ void SharedWorkerManager::ErrorReceived(
 void SharedWorkerManager::Terminated() {
   AssertIsOnBackgroundThread();
 
   for (SharedWorkerParent* actor : mActors) {
     Unused << actor->SendTerminate();
   }
 }
 
+void SharedWorkerManager::RegisterHolder(SharedWorkerManagerHolder* aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHolder);
+  MOZ_ASSERT(!mHolders.Contains(aHolder));
+
+  mHolders.AppendElement(aHolder);
+}
+
+void SharedWorkerManager::UnregisterHolder(SharedWorkerManagerHolder* aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHolder);
+  MOZ_ASSERT(mHolders.Contains(aHolder));
+
+  mHolders.RemoveElement(aHolder);
+
+  if (!mHolders.IsEmpty()) {
+    return;
+  }
+
+  // Time to go.
+
+  aHolder->Service()->RemoveWorkerManagerOnMainThread(this);
+
+  RefPtr<SharedWorkerManager> self = this;
+  mPBackgroundEventTarget->Dispatch(
+      NS_NewRunnableFunction(
+          "SharedWorkerService::RemoveWorkerManagerOnMainThread",
+          [self]() { self->Terminate(); }),
+      NS_DISPATCH_NORMAL);
+}
+
+SharedWorkerManagerHolder::SharedWorkerManagerHolder(
+    SharedWorkerManager* aManager, SharedWorkerService* aService)
+    : mManager(aManager), mService(aService) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aService);
+
+  aManager->RegisterHolder(this);
+}
+
+SharedWorkerManagerHolder::~SharedWorkerManagerHolder() {
+  MOZ_ASSERT(NS_IsMainThread());
+  mManager->UnregisterHolder(this);
+}
+
+SharedWorkerManagerWrapper::SharedWorkerManagerWrapper(
+    already_AddRefed<SharedWorkerManagerHolder> aHolder)
+    : mHolder(aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+SharedWorkerManagerWrapper::~SharedWorkerManagerWrapper() {
+  NS_ReleaseOnMainThreadSystemGroup("SharedWorkerManagerWrapper::mHolder",
+                                    mHolder.forget());
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorkerManager.h
+++ b/dom/workers/sharedworkers/SharedWorkerManager.h
@@ -13,31 +13,73 @@
 
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortIdentifier;
 class RemoteWorkerData;
+class SharedWorkerManager;
+class SharedWorkerService;
 class SharedWorkerParent;
 
+// Main-thread only object that keeps a manager and the service alive.
+// When the last SharedWorkerManagerHolder is released, the corresponding
+// manager unregisters itself from the service and terminates the worker.
+class SharedWorkerManagerHolder final {
+ public:
+  NS_INLINE_DECL_REFCOUNTING(SharedWorkerManagerHolder);
+
+  SharedWorkerManagerHolder(SharedWorkerManager* aManager,
+                            SharedWorkerService* aService);
+
+  SharedWorkerManager* Manager() const { return mManager; }
+
+  SharedWorkerService* Service() const { return mService; }
+
+ private:
+  ~SharedWorkerManagerHolder();
+
+  RefPtr<SharedWorkerManager> mManager;
+  RefPtr<SharedWorkerService> mService;
+};
+
+// Thread-safe wrapper for SharedWorkerManagerHolder.
+class SharedWorkerManagerWrapper final {
+ public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManagerWrapper);
+
+  explicit SharedWorkerManagerWrapper(
+      already_AddRefed<SharedWorkerManagerHolder> aHolder);
+
+  SharedWorkerManager* Manager() const { return mHolder->Manager(); }
+
+ private:
+  ~SharedWorkerManagerWrapper();
+
+  RefPtr<SharedWorkerManagerHolder> mHolder;
+};
+
 class SharedWorkerManager final : public RemoteWorkerObserver {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManager, override);
 
   // Called on main-thread thread methods
 
-  SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
-                      const RemoteWorkerData& aData,
-                      nsIPrincipal* aLoadingPrincipal);
+  static already_AddRefed<SharedWorkerManagerHolder> Create(
+      SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
+      const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal);
 
-  bool MatchOnMainThread(const nsACString& aDomain, nsIURI* aScriptURL,
-                         const nsAString& aName,
-                         nsIPrincipal* aLoadingPrincipal) const;
+  // Returns a holder if this manager matches. The holder blocks the shutdown of
+  // the manager.
+  already_AddRefed<SharedWorkerManagerHolder> MatchOnMainThread(
+      SharedWorkerService* aService, const nsACString& aDomain,
+      nsIURI* aScriptURL, const nsAString& aName,
+      nsIPrincipal* aLoadingPrincipal);
 
   // RemoteWorkerObserver
 
   void CreationFailed() override;
 
   void CreationSucceeded() override;
 
   void ErrorReceived(const ErrorValue& aValue) override;
@@ -56,17 +98,29 @@ class SharedWorkerManager final : public
   void RemoveActor(SharedWorkerParent* aParent);
 
   void UpdateSuspend();
 
   void UpdateFrozen();
 
   bool IsSecureContext() const;
 
+  void Terminate();
+
+  // Called on main-thread only.
+
+  void RegisterHolder(SharedWorkerManagerHolder* aHolder);
+
+  void UnregisterHolder(SharedWorkerManagerHolder* aHolder);
+
  private:
+  SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
+                      const RemoteWorkerData& aData,
+                      nsIPrincipal* aLoadingPrincipal);
+
   ~SharedWorkerManager();
 
   nsCOMPtr<nsIEventTarget> mPBackgroundEventTarget;
 
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
   nsCString mDomain;
   nsCOMPtr<nsIURI> mResolvedScriptURL;
   nsString mName;
@@ -74,14 +128,18 @@ class SharedWorkerManager final : public
   bool mSuspended;
   bool mFrozen;
 
   // Raw pointers because SharedWorkerParent unregisters itself in
   // ActorDestroy().
   nsTArray<SharedWorkerParent*> mActors;
 
   RefPtr<RemoteWorkerController> mRemoteWorkerController;
+
+  // Main-thread only. Raw Pointers because holders keep the manager alive and
+  // they unregister themselves in their DTOR.
+  nsTArray<SharedWorkerManagerHolder*> mHolders;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SharedWorkerManager_h
--- a/dom/workers/sharedworkers/SharedWorkerParent.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp
@@ -26,130 +26,131 @@ SharedWorkerParent::SharedWorkerParent()
   AssertIsOnBackgroundThread();
 }
 
 SharedWorkerParent::~SharedWorkerParent() = default;
 
 void SharedWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason aReason) {
   AssertIsOnBackgroundThread();
 
-  if (mWorkerManager) {
-    mWorkerManager->RemoveActor(this);
-    mWorkerManager = nullptr;
+  if (mWorkerManagerWrapper) {
+    mWorkerManagerWrapper->Manager()->RemoveActor(this);
+    mWorkerManagerWrapper = nullptr;
   }
 }
 
 void SharedWorkerParent::Initialize(
     const RemoteWorkerData& aData, uint64_t aWindowID,
     const MessagePortIdentifier& aPortIdentifier) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == eInit);
 
-  // Let's keep the service alive.
-  mService = SharedWorkerService::GetOrCreate();
-  MOZ_ASSERT(mService);
-
   mWindowID = aWindowID;
 
   mStatus = ePending;
-  mService->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
+
+  RefPtr<SharedWorkerService> service = SharedWorkerService::GetOrCreate();
+  MOZ_ASSERT(service);
+  service->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
 }
 
 IPCResult SharedWorkerParent::RecvClose() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mStatus = eClosed;
 
-  if (mWorkerManager) {
-    mWorkerManager->RemoveActor(this);
-    mWorkerManager = nullptr;
+  if (mWorkerManagerWrapper) {
+    mWorkerManagerWrapper->Manager()->RemoveActor(this);
+    mWorkerManagerWrapper = nullptr;
   }
 
   Unused << Send__delete__(this);
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvSuspend() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mSuspended);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mSuspended = true;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateSuspend();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateSuspend();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvResume() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mSuspended);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mSuspended = false;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateSuspend();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateSuspend();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvFreeze() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mFrozen);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mFrozen = true;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateFrozen();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateFrozen();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvThaw() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mFrozen);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mFrozen = false;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateFrozen();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateFrozen();
   }
 
   return IPC_OK();
 }
 
-void SharedWorkerParent::ManagerCreated(SharedWorkerManager* aWorkerManager) {
+void SharedWorkerParent::ManagerCreated(
+    already_AddRefed<SharedWorkerManagerWrapper> aWorkerManagerWrapper) {
   AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aWorkerManager);
-  MOZ_ASSERT(!mWorkerManager);
+  MOZ_ASSERT(!mWorkerManagerWrapper);
   MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
 
+  RefPtr<SharedWorkerManagerWrapper> wrapper = aWorkerManagerWrapper;
+
   // Already gone.
   if (mStatus == eClosed) {
-    aWorkerManager->RemoveActor(this);
+    wrapper->Manager()->RemoveActor(this);
     return;
   }
 
   mStatus = eActive;
-  mWorkerManager = aWorkerManager;
+  mWorkerManagerWrapper = wrapper;
 
-  mWorkerManager->UpdateFrozen();
-  mWorkerManager->UpdateSuspend();
+  mWorkerManagerWrapper->Manager()->UpdateFrozen();
+  mWorkerManagerWrapper->Manager()->UpdateSuspend();
 }
 
 void SharedWorkerParent::ErrorPropagation(nsresult aError) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(NS_FAILED(aError));
   MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
 
   // Already gone.
--- a/dom/workers/sharedworkers/SharedWorkerParent.h
+++ b/dom/workers/sharedworkers/SharedWorkerParent.h
@@ -11,29 +11,29 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortIdentifier;
 class RemoteWorkerData;
-class SharedWorkerManager;
-class SharedWorkerService;
+class SharedWorkerManagerWrapper;
 
 class SharedWorkerParent final : public mozilla::dom::PSharedWorkerParent {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerParent)
 
   SharedWorkerParent();
 
   void Initialize(const RemoteWorkerData& aData, uint64_t aWindowID,
                   const MessagePortIdentifier& aPortIdentifier);
 
-  void ManagerCreated(SharedWorkerManager* aWorkerManager);
+  void ManagerCreated(
+      already_AddRefed<SharedWorkerManagerWrapper> aWorkerManagerWrapper);
 
   void ErrorPropagation(nsresult aError);
 
   mozilla::ipc::IPCResult RecvClose();
 
   mozilla::ipc::IPCResult RecvSuspend();
 
   mozilla::ipc::IPCResult RecvResume();
@@ -49,18 +49,17 @@ class SharedWorkerParent final : public 
   uint64_t WindowID() const { return mWindowID; }
 
  private:
   ~SharedWorkerParent();
 
   void ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
 
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
-  RefPtr<SharedWorkerManager> mWorkerManager;
-  RefPtr<SharedWorkerService> mService;
+  RefPtr<SharedWorkerManagerWrapper> mWorkerManagerWrapper;
 
   enum {
     eInit,
     ePending,
     eActive,
     eClosed,
   } mStatus;
 
--- a/dom/workers/sharedworkers/SharedWorkerService.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerService.cpp
@@ -4,28 +4,30 @@
  * 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 "SharedWorkerService.h"
 #include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/SystemGroup.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 namespace {
 
 StaticMutex sSharedWorkerMutex;
 
-// Raw pointer because SharedWorkerParent keeps this object alive.
+// Raw pointer because SharedWorkerParent keeps this object alive, indirectly
+// via SharedWorkerManagerHolder.
 SharedWorkerService* MOZ_NON_OWNING_REF sSharedWorkerService;
 
 nsresult PopulateContentSecurityPolicy(
     nsIContentSecurityPolicy* aCSP,
     const nsTArray<ContentSecurityPolicy>& aPolicies) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aCSP);
   MOZ_ASSERT(!aPolicies.IsEmpty());
@@ -65,100 +67,76 @@ nsresult PopulatePrincipalContentSecurit
     }
   }
 
   return NS_OK;
 }
 
 class GetOrCreateWorkerManagerRunnable final : public Runnable {
  public:
-  GetOrCreateWorkerManagerRunnable(SharedWorkerParent* aActor,
+  GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService,
+                                   SharedWorkerParent* aActor,
                                    const RemoteWorkerData& aData,
                                    uint64_t aWindowID,
                                    const MessagePortIdentifier& aPortIdentifier)
       : Runnable("GetOrCreateWorkerManagerRunnable"),
         mBackgroundEventTarget(GetCurrentThreadEventTarget()),
+        mService(aService),
         mActor(aActor),
         mData(aData),
         mWindowID(aWindowID),
         mPortIdentifier(aPortIdentifier) {}
 
   NS_IMETHOD
   Run() {
-    // The service is always available because it's kept alive by the actor.
-    SharedWorkerService* service = SharedWorkerService::Get();
-    MOZ_ASSERT(service);
-
-    service->GetOrCreateWorkerManagerOnMainThread(
+    mService->GetOrCreateWorkerManagerOnMainThread(
         mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier);
 
     return NS_OK;
   }
 
  private:
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+  RefPtr<SharedWorkerService> mService;
   RefPtr<SharedWorkerParent> mActor;
   RemoteWorkerData mData;
   uint64_t mWindowID;
   MessagePortIdentifier mPortIdentifier;
 };
 
-class RemoveWorkerManagerRunnable final : public Runnable {
- public:
-  RemoveWorkerManagerRunnable(SharedWorkerService* aService,
-                              SharedWorkerManager* aManager)
-      : Runnable("RemoveWorkerManagerRunnable"),
-        mService(aService),
-        mManager(aManager) {
-    MOZ_ASSERT(mService);
-    MOZ_ASSERT(mManager);
-  }
-
-  NS_IMETHOD
-  Run() {
-    mService->RemoveWorkerManagerOnMainThread(mManager);
-    return NS_OK;
-  }
-
- private:
-  RefPtr<SharedWorkerService> mService;
-  RefPtr<SharedWorkerManager> mManager;
-};
-
 class WorkerManagerCreatedRunnable final : public Runnable {
  public:
-  WorkerManagerCreatedRunnable(SharedWorkerManager* aManager,
-                               SharedWorkerParent* aActor,
-                               const RemoteWorkerData& aData,
-                               uint64_t aWindowID,
-                               const MessagePortIdentifier& aPortIdentifier)
+  WorkerManagerCreatedRunnable(
+      already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper,
+      SharedWorkerParent* aActor, const RemoteWorkerData& aData,
+      uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier)
       : Runnable("WorkerManagerCreatedRunnable"),
-        mManager(aManager),
+        mManagerWrapper(aManagerWrapper),
         mActor(aActor),
         mData(aData),
         mWindowID(aWindowID),
         mPortIdentifier(aPortIdentifier) {}
 
   NS_IMETHOD
   Run() {
     AssertIsOnBackgroundThread();
 
-    if (NS_WARN_IF(!mManager->MaybeCreateRemoteWorker(
+    if (NS_WARN_IF(!mManagerWrapper->Manager()->MaybeCreateRemoteWorker(
             mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) {
       mActor->ErrorPropagation(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
-    mManager->AddActor(mActor);
-    mActor->ManagerCreated(mManager);
+    mManagerWrapper->Manager()->AddActor(mActor);
+    mActor->ManagerCreated(mManagerWrapper.forget());
     return NS_OK;
   }
 
  private:
-  RefPtr<SharedWorkerManager> mManager;
+  RefPtr<SharedWorkerManagerWrapper> mManagerWrapper;
   RefPtr<SharedWorkerParent> mActor;
   RemoteWorkerData mData;
   uint64_t mWindowID;
   MessagePortIdentifier mPortIdentifier;
 };
 
 class ErrorPropagationRunnable final : public Runnable {
  public:
@@ -218,35 +196,33 @@ SharedWorkerService::~SharedWorkerServic
 
 void SharedWorkerService::GetOrCreateWorkerManager(
     SharedWorkerParent* aActor, const RemoteWorkerData& aData,
     uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) {
   AssertIsOnBackgroundThread();
 
   // The real check happens on main-thread.
   RefPtr<GetOrCreateWorkerManagerRunnable> r =
-      new GetOrCreateWorkerManagerRunnable(aActor, aData, aWindowID,
+      new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID,
                                            aPortIdentifier);
 
   nsCOMPtr<nsIEventTarget> target =
       SystemGroup::EventTargetFor(TaskCategory::Other);
   nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 }
 
 void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
     nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
     const RemoteWorkerData& aData, uint64_t aWindowID,
     const MessagePortIdentifier& aPortIdentifier) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBackgroundEventTarget);
   MOZ_ASSERT(aActor);
 
-  RefPtr<SharedWorkerManager> manager;
-
   nsresult rv = NS_OK;
   nsCOMPtr<nsIPrincipal> principal =
       PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
   if (NS_WARN_IF(!principal)) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
@@ -267,73 +243,67 @@ void SharedWorkerService::GetOrCreateWor
   rv = PopulatePrincipalContentSecurityPolicy(
       loadingPrincipal, aData.loadingPrincipalCsp(),
       aData.loadingPrincipalPreloadCsp());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
+  RefPtr<SharedWorkerManagerHolder> managerHolder;
+
   // Let's see if there is already a SharedWorker to share.
   nsCOMPtr<nsIURI> resolvedScriptURL =
       DeserializeURI(aData.resolvedScriptURL());
   for (SharedWorkerManager* workerManager : mWorkerManagers) {
-    if (workerManager->MatchOnMainThread(aData.domain(), resolvedScriptURL,
-                                         aData.name(), loadingPrincipal)) {
-      manager = workerManager;
+    managerHolder = workerManager->MatchOnMainThread(
+        this, aData.domain(), resolvedScriptURL, aData.name(),
+        loadingPrincipal);
+    if (managerHolder) {
       break;
     }
   }
 
   // Let's create a new one.
-  if (!manager) {
-    manager = new SharedWorkerManager(aBackgroundEventTarget, aData,
-                                      loadingPrincipal);
+  if (!managerHolder) {
+    managerHolder = SharedWorkerManager::Create(this, aBackgroundEventTarget,
+                                                aData, loadingPrincipal);
 
-    mWorkerManagers.AppendElement(manager);
+    mWorkerManagers.AppendElement(managerHolder->Manager());
   } else {
     // We are attaching the actor to an existing one.
-    if (manager->IsSecureContext() != aData.isSecureContext()) {
+    if (managerHolder->Manager()->IsSecureContext() !=
+        aData.isSecureContext()) {
       ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
                                    NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
   }
 
+  RefPtr<SharedWorkerManagerWrapper> wrapper =
+      new SharedWorkerManagerWrapper(managerHolder.forget());
+
   RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable(
-      manager, aActor, aData, aWindowID, aPortIdentifier);
+      wrapper.forget(), aActor, aData, aWindowID, aPortIdentifier);
   aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void SharedWorkerService::ErrorPropagationOnMainThread(
     nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
     nsresult aError) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBackgroundEventTarget);
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(NS_FAILED(aError));
 
   RefPtr<ErrorPropagationRunnable> r =
       new ErrorPropagationRunnable(aActor, aError);
   aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
-void SharedWorkerService::RemoveWorkerManager(SharedWorkerManager* aManager) {
-  AssertIsOnBackgroundThread();
-
-  // We pass 'this' in order to be kept alive.
-  RefPtr<RemoveWorkerManagerRunnable> r =
-      new RemoveWorkerManagerRunnable(this, aManager);
-
-  nsCOMPtr<nsIEventTarget> target =
-      SystemGroup::EventTargetFor(TaskCategory::Other);
-  nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
-  Unused << NS_WARN_IF(NS_FAILED(rv));
-}
-
 void SharedWorkerService::RemoveWorkerManagerOnMainThread(
     SharedWorkerManager* aManager) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mWorkerManagers.Contains(aManager));
 
   mWorkerManagers.RemoveElement(aManager);
 }
--- a/dom/workers/sharedworkers/SharedWorkerService.h
+++ b/dom/workers/sharedworkers/SharedWorkerService.h
@@ -40,19 +40,16 @@ class SharedWorkerService final {
                                 uint64_t aWindowID,
                                 const MessagePortIdentifier& aPortIdentifier);
 
   void GetOrCreateWorkerManagerOnMainThread(
       nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
       const RemoteWorkerData& aData, uint64_t aWindowID,
       const MessagePortIdentifier& aPortIdentifier);
 
-  // PBackground method only.
-  void RemoveWorkerManager(SharedWorkerManager* aManager);
-
   void RemoveWorkerManagerOnMainThread(SharedWorkerManager* aManager);
 
  private:
   SharedWorkerService();
   ~SharedWorkerService();
 
   void ErrorPropagationOnMainThread(nsIEventTarget* aBackgroundEventTarget,
                                     SharedWorkerParent* aActor,