Bug 1420594 P2 Eagerly shutdown ClientManagerService. r=baku a=aryx on CLOSED TREE

This commit is contained in:
Ben Kelly 2017-12-01 14:48:11 -05:00
Родитель 5bd2e38996
Коммит 76d6394334
2 изменённых файлов: 147 добавлений и 0 удалений

Просмотреть файл

@ -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,105 @@ 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 ref.forget();
}
} // anonymous namespace
ClientManagerService::ClientManagerService()
: mShutdown(false)
{
AssertIsOnBackgroundThread();
// 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.
OnShutdown()->Then(GetCurrentThreadSerialEventTarget(), __func__,
[] () {
RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
if (svc) {
svc->Shutdown();
}
});
}
ClientManagerService::~ClientManagerService()
@ -73,6 +171,26 @@ ClientManagerService::~ClientManagerService()
sClientManagerServiceInstance = nullptr;
}
void
ClientManagerService::Shutdown()
{
AssertIsOnBackgroundThread();
// If many ClientManagerService are created and destroyed quickly we can
// in theory get more than one shutdown listener calling us.
if (mShutdown) {
return;
}
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()
@ -87,6 +205,20 @@ ClientManagerService::GetOrCreateInstance()
return ref.forget();
}
// static
already_AddRefed<ClientManagerService>
ClientManagerService::GetInstance()
{
AssertIsOnBackgroundThread();
if (!sClientManagerServiceInstance) {
return nullptr;
}
RefPtr<ClientManagerService> ref(sClientManagerServiceInstance);
return ref.forget();
}
bool
ClientManagerService::AddSource(ClientSourceParent* aSource)
{
@ -142,6 +274,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,13 +28,22 @@ class ClientManagerService final
nsTArray<ClientManagerParent*> mManagerList;
bool mShutdown;
ClientManagerService();
~ClientManagerService();
void
Shutdown();
public:
static already_AddRefed<ClientManagerService>
GetOrCreateInstance();
// Returns nullptr if the service is not already created.
static already_AddRefed<ClientManagerService>
GetInstance();
bool
AddSource(ClientSourceParent* aSource);