mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 04:45:45 +00:00
Bug 1420594 P2 Eagerly shutdown ClientManagerService. r=baku
This commit is contained in:
parent
0031cd668f
commit
559339f71a
@ -6,9 +6,13 @@
|
||||
|
||||
#include "ClientManagerService.h"
|
||||
|
||||
#include "ClientManagerParent.h"
|
||||
#include "ClientSourceParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -56,11 +60,107 @@ MatchPrincipalInfo(const PrincipalInfo& aLeft, const PrincipalInfo& aRight)
|
||||
MOZ_CRASH("unexpected principal type!");
|
||||
}
|
||||
|
||||
class ClientShutdownBlocker final : public nsIAsyncShutdownBlocker
|
||||
{
|
||||
RefPtr<GenericPromise::Private> mPromise;
|
||||
|
||||
~ClientShutdownBlocker() = default;
|
||||
|
||||
public:
|
||||
explicit ClientShutdownBlocker(GenericPromise::Private* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromise);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetName(nsAString& aNameOut) override
|
||||
{
|
||||
aNameOut =
|
||||
NS_LITERAL_STRING("ClientManagerService: start destroying IPC actors early");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
BlockShutdown(nsIAsyncShutdownClient* aClient) override
|
||||
{
|
||||
mPromise->Resolve(true, __func__);
|
||||
aClient->RemoveBlocker(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetState(nsIPropertyBag**) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClientShutdownBlocker, nsIAsyncShutdownBlocker)
|
||||
|
||||
// Helper function the resolves a MozPromise when we detect that the browser
|
||||
// has begun to shutdown.
|
||||
RefPtr<GenericPromise>
|
||||
OnShutdown()
|
||||
{
|
||||
RefPtr<GenericPromise::Private> ref = new GenericPromise::Private(__func__);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("ClientManagerServer::OnShutdown",
|
||||
[ref] () {
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
|
||||
if (!svc) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownClient> phase;
|
||||
MOZ_ALWAYS_SUCCEEDS(svc->GetXpcomWillShutdown(getter_AddRefs(phase)));
|
||||
if (!phase) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownBlocker> blocker = new ClientShutdownBlocker(ref);
|
||||
nsresult rv =
|
||||
phase->AddBlocker(blocker, NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("ClientManagerService shutdown"));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
|
||||
|
||||
return Move(ref);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ClientManagerService::ClientManagerService()
|
||||
: mShutdown(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<ClientManagerService> self = this;
|
||||
|
||||
// While the ClientManagerService will be gracefully terminated as windows
|
||||
// and workers are naturally killed, this can cause us to do extra work
|
||||
// relatively late in the shutdown process. To avoid this we eagerly begin
|
||||
// shutdown at the first sign it has begun. Since we handle normal shutdown
|
||||
// gracefully we don't really need to block anything here. We just begin
|
||||
// destroying our IPC actors immediately.
|
||||
//
|
||||
// Note. capture the self reference here will keep the service alive until
|
||||
// shutdown. This is what almost always happens anyway, though.
|
||||
OnShutdown()->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[self] () {
|
||||
self->Shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
ClientManagerService::~ClientManagerService()
|
||||
@ -73,6 +173,24 @@ ClientManagerService::~ClientManagerService()
|
||||
sClientManagerServiceInstance = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ClientManagerService::Shutdown()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Our shutdown promise should really only resolve once. So double-shutdown
|
||||
// is not expected
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
|
||||
mShutdown = true;
|
||||
|
||||
// Begin destroying our various manager actors which will in turn destroy
|
||||
// all source, handle, and operation actors.
|
||||
AutoTArray<ClientManagerParent*, 16> list(mManagerList);
|
||||
for (auto actor : list) {
|
||||
Unused << PClientManagerParent::Send__delete__(actor);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ClientManagerService>
|
||||
ClientManagerService::GetOrCreateInstance()
|
||||
@ -142,6 +260,11 @@ ClientManagerService::AddManager(ClientManagerParent* aManager)
|
||||
MOZ_DIAGNOSTIC_ASSERT(aManager);
|
||||
MOZ_ASSERT(!mManagerList.Contains(aManager));
|
||||
mManagerList.AppendElement(aManager);
|
||||
|
||||
// If shutdown has already begun then immediately destroy the actor.
|
||||
if (mShutdown) {
|
||||
Unused << PClientManagerParent::Send__delete__(aManager);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define _mozilla_dom_ClientManagerService_h
|
||||
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -27,9 +28,14 @@ class ClientManagerService final
|
||||
|
||||
nsTArray<ClientManagerParent*> mManagerList;
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
ClientManagerService();
|
||||
~ClientManagerService();
|
||||
|
||||
void
|
||||
Shutdown();
|
||||
|
||||
public:
|
||||
static already_AddRefed<ClientManagerService>
|
||||
GetOrCreateInstance();
|
||||
|
Loading…
Reference in New Issue
Block a user