diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 63e832e8bbb9..62423c375f9a 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1862,6 +1862,11 @@ ContentParent::ShouldKeepProcessAlive() const return true; } + // If we have active workers, we need to stay alive. + if (mRemoteWorkerActors) { + return true; + } + if (!sBrowserContentParents) { return false; } @@ -2385,6 +2390,7 @@ ContentParent::ContentParent(ContentParent* aOpener, , mChildID(gContentChildID++) , mGeolocationWatchID(-1) , mJSPluginID(aJSPluginID) + , mRemoteWorkerActors(0) , mNumDestroyingTabs(0) , mIsAvailable(true) , mIsAlive(true) @@ -6162,3 +6168,32 @@ ContentParent::RecvSetOpenerBrowsingContext( return IPC_OK(); } + +void +ContentParent::RegisterRemoteWorkerActor() +{ + ++mRemoteWorkerActors; +} + +void +ContentParent::UnregisterRemoveWorkerActor() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (--mRemoteWorkerActors) { + return; + } + + ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); + if (!cpm->GetTabParentCountByProcessId(ChildID()) && + !ShouldKeepProcessAlive() && + !TryToRecycle()) { + // In the case of normal shutdown, send a shutdown message to child to + // allow it to perform shutdown tasks. + MessageLoop::current()->PostTask( + NewRunnableMethod("dom::ContentParent::ShutDownProcess", + this, + &ContentParent::ShutDownProcess, + SEND_SHUTDOWN_MESSAGE)); + } +} diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 16c8d407b4e3..898fb5763324 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -363,6 +363,15 @@ public: const ContentParentId& aCpId, bool aMarkedDestroying); + // This method can be called on any thread. + void + RegisterRemoteWorkerActor(); + + // This method _must_ be called on main-thread because it can start the + // shutting down of the content process. + void + UnregisterRemoveWorkerActor(); + void ReportChildAlreadyBlocked(); bool RequestRunToCompletion(); @@ -1300,6 +1309,13 @@ private: // SIGSTOP), are still killed eventually. This task enforces that // timer. nsCOMPtr mForceKillTimer; + + // Number of active remote workers. This value is increased when a + // RemoteWorkerParent actor is created for this ContentProcess and it is + // decreased when the actor is destroyed. + // It's touched on PBackground thread and on main-thread. + Atomic mRemoteWorkerActors; + // How many tabs we're waiting to finish their destruction // sequence. Precisely, how many TabParents have called // NotifyTabDestroying() but not called NotifyTabDestroyed(). diff --git a/dom/workers/remoteworkers/RemoteWorkerManager.cpp b/dom/workers/remoteworkers/RemoteWorkerManager.cpp index 5a7ac8a19c83..0d01b07f5cf6 100644 --- a/dom/workers/remoteworkers/RemoteWorkerManager.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerManager.cpp @@ -139,6 +139,8 @@ RemoteWorkerManager::LaunchInternal(RemoteWorkerController* aController, return; } + workerActor->Initialize(); + // This makes the link better the 2 actors. aController->SetWorkerActor(workerActor); workerActor->SetController(aController); diff --git a/dom/workers/remoteworkers/RemoteWorkerParent.cpp b/dom/workers/remoteworkers/RemoteWorkerParent.cpp index 6fcbe11088fe..9a2823602ac9 100644 --- a/dom/workers/remoteworkers/RemoteWorkerParent.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerParent.cpp @@ -6,8 +6,10 @@ #include "RemoteWorkerParent.h" #include "RemoteWorkerController.h" +#include "mozilla/dom/ContentParent.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/Unused.h" +#include "nsProxyRelease.h" namespace mozilla { @@ -15,6 +17,35 @@ using namespace ipc; namespace dom { +namespace { + +class UnregisterActorRunnable final : public Runnable +{ +public: + explicit UnregisterActorRunnable(already_AddRefed aParent) + : Runnable("UnregisterActorRunnable") + , mContentParent(aParent) + { + AssertIsOnBackgroundThread(); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + + mContentParent->UnregisterRemoveWorkerActor(); + mContentParent = nullptr; + + return NS_OK; + } + +private: + RefPtr mContentParent; +}; + +} // anonymous + RemoteWorkerParent::RemoteWorkerParent() { AssertIsOnBackgroundThread(); @@ -27,12 +58,41 @@ RemoteWorkerParent::~RemoteWorkerParent() MOZ_ASSERT(XRE_IsParentProcess()); } +void +RemoteWorkerParent::Initialize() +{ + RefPtr parent = BackgroundParent::GetContentParent(Manager()); + + // Parent is null if the child actor runs on the parent process. + if (parent) { + parent->RegisterRemoteWorkerActor(); + + nsCOMPtr target = + SystemGroup::EventTargetFor(TaskCategory::Other); + + NS_ProxyRelease("RemoteWorkerParent::Initialize ContentParent", + target, parent.forget()); + } +} + void RemoteWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason) { AssertIsOnBackgroundThread(); MOZ_ASSERT(XRE_IsParentProcess()); + RefPtr parent = BackgroundParent::GetContentParent(Manager()); + + // Parent is null if the child actor runs on the parent process. + if (parent) { + RefPtr r = + new UnregisterActorRunnable(parent.forget()); + + nsCOMPtr target = + SystemGroup::EventTargetFor(TaskCategory::Other); + target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); + } + mController = nullptr; } diff --git a/dom/workers/remoteworkers/RemoteWorkerParent.h b/dom/workers/remoteworkers/RemoteWorkerParent.h index 3608e067f7cc..30e44566339a 100644 --- a/dom/workers/remoteworkers/RemoteWorkerParent.h +++ b/dom/workers/remoteworkers/RemoteWorkerParent.h @@ -21,6 +21,9 @@ public: RemoteWorkerParent(); + void + Initialize(); + void SetController(RemoteWorkerController* aController);