mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1653060 - P4. Wait until all MediaRemoteDecoderManagerParent have closed before killing process. r=mattwoodrow.
We unfortunately can't use the AsyncShutdownService in either the GPU or RDD process. So we add a little utility class AsyncBlockers that will resolve its promise once all services have deregistered from it. We use it to temporily suspend the RDDParent or GPUParent from killing the process, up to 10s. This allows for cleaner shutdown as the parent process doesn't guarantee the order in which processes are killed (even though it should). Differential Revision: https://phabricator.services.mozilla.com/D90487
This commit is contained in:
parent
e748bb2d7b
commit
298b6203a1
@ -53,7 +53,10 @@ RDDParent::RDDParent() : mLaunchTime(TimeStamp::Now()) { sRDDParent = this; }
|
||||
RDDParent::~RDDParent() { sRDDParent = nullptr; }
|
||||
|
||||
/* static */
|
||||
RDDParent* RDDParent::GetSingleton() { return sRDDParent; }
|
||||
RDDParent* RDDParent::GetSingleton() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(sRDDParent);
|
||||
return sRDDParent;
|
||||
}
|
||||
|
||||
bool RDDParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
||||
MessageLoop* aIOLoop, UniquePtr<IPC::Channel> aChannel) {
|
||||
@ -210,23 +213,28 @@ void RDDParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
ProcessChild::QuickExit();
|
||||
#endif
|
||||
|
||||
// Wait until all RemoteDecoderManagerParent have closed.
|
||||
mShutdownBlockers.WaitUntilClear(10 * 1000 /* 10s timeout*/)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__, [this]() {
|
||||
|
||||
#if defined(XP_WIN)
|
||||
RefPtr<DllServices> dllSvc(DllServices::Get());
|
||||
dllSvc->DisableFull();
|
||||
RefPtr<DllServices> dllSvc(DllServices::Get());
|
||||
dllSvc->DisableFull();
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (mProfilerController) {
|
||||
mProfilerController->Shutdown();
|
||||
mProfilerController = nullptr;
|
||||
}
|
||||
if (mProfilerController) {
|
||||
mProfilerController->Shutdown();
|
||||
mProfilerController = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
RemoteDecoderManagerParent::ShutdownVideoBridge();
|
||||
RemoteDecoderManagerParent::ShutdownVideoBridge();
|
||||
|
||||
gfxVars::Shutdown();
|
||||
CrashReporterClient::DestroySingleton();
|
||||
XRE_ShutdownChildProcess();
|
||||
gfxVars::Shutdown();
|
||||
CrashReporterClient::DestroySingleton();
|
||||
XRE_ShutdownChildProcess();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "mozilla/PRDDParent.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/media/MediaUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -21,6 +22,8 @@ class RDDParent final : public PRDDParent {
|
||||
|
||||
static RDDParent* GetSingleton();
|
||||
|
||||
AsyncBlockers& AsyncShutdownService() { return mShutdownBlockers; }
|
||||
|
||||
bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
||||
MessageLoop* aIOLoop, UniquePtr<IPC::Channel> aChannel);
|
||||
|
||||
@ -51,6 +54,7 @@ class RDDParent final : public PRDDParent {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
RefPtr<ChildProfilerController> mProfilerController;
|
||||
#endif
|
||||
AsyncBlockers mShutdownBlockers;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/VideoBridgeChild.h"
|
||||
#include "mozilla/gfx/GPUParent.h"
|
||||
#include "mozilla/RDDParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -149,10 +151,18 @@ RemoteDecoderManagerParent::RemoteDecoderManagerParent(
|
||||
nsISerialEventTarget* aThread)
|
||||
: mThread(aThread) {
|
||||
MOZ_COUNT_CTOR(RemoteDecoderManagerParent);
|
||||
auto& registrar = XRE_IsGPUProcess()
|
||||
? GPUParent::GetSingleton()->AsyncShutdownService()
|
||||
: RDDParent::GetSingleton()->AsyncShutdownService();
|
||||
registrar.Register(this);
|
||||
}
|
||||
|
||||
RemoteDecoderManagerParent::~RemoteDecoderManagerParent() {
|
||||
MOZ_COUNT_DTOR(RemoteDecoderManagerParent);
|
||||
auto& registrar = XRE_IsGPUProcess()
|
||||
? GPUParent::GetSingleton()->AsyncShutdownService()
|
||||
: RDDParent::GetSingleton()->AsyncShutdownService();
|
||||
registrar.Deregister(this);
|
||||
}
|
||||
|
||||
void RemoteDecoderManagerParent::ActorDestroy(
|
||||
|
@ -7,9 +7,12 @@
|
||||
#ifndef mozilla_MediaUtils_h
|
||||
#define mozilla_MediaUtils_h
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
@ -293,6 +296,89 @@ AwaitAll(already_AddRefed<nsIEventTarget> aPool,
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
||||
/**
|
||||
* AsyncBlockers provide a simple registration service that allows to suspend
|
||||
* completion of a particular task until all registered entries have been
|
||||
* cleared. This can be used to implement a similar service to
|
||||
* nsAsyncShutdownService in processes where it wouldn't normally be available.
|
||||
* This class is thread-safe.
|
||||
*/
|
||||
class AsyncBlockers {
|
||||
public:
|
||||
AsyncBlockers()
|
||||
: mLock("AsyncRegistrar"),
|
||||
mPromise(new GenericPromise::Private(__func__)) {}
|
||||
void Register(void* aBlocker) {
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mResolved) {
|
||||
// Too late.
|
||||
return;
|
||||
}
|
||||
mBlockers.insert({aBlocker, true});
|
||||
}
|
||||
void Deregister(void* aBlocker) {
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mResolved) {
|
||||
// Too late.
|
||||
return;
|
||||
}
|
||||
auto it = mBlockers.find(aBlocker);
|
||||
MOZ_ASSERT(it != mBlockers.end());
|
||||
|
||||
mBlockers.erase(it);
|
||||
MaybeResolve();
|
||||
}
|
||||
RefPtr<GenericPromise> WaitUntilClear(uint32_t aTimeOutInMs = 0) {
|
||||
if (!aTimeOutInMs) {
|
||||
// We don't need to wait, resolve the promise right away.
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mResolved) {
|
||||
mPromise->Resolve(true, __func__);
|
||||
mResolved = true;
|
||||
}
|
||||
} else {
|
||||
GetCurrentEventTarget()->DelayedDispatch(
|
||||
NS_NewRunnableFunction("AsyncBlockers::WaitUntilClear",
|
||||
[promise = mPromise]() {
|
||||
// The AsyncBlockers object may have been
|
||||
// deleted by now and the object isn't
|
||||
// refcounted (nor do we want it to be). We
|
||||
// can unconditionally resolve the promise
|
||||
// even it has already been resolved as
|
||||
// MozPromise are thread-safe and will just
|
||||
// ignore the action if already resolved.
|
||||
promise->Resolve(true, __func__);
|
||||
}),
|
||||
aTimeOutInMs);
|
||||
}
|
||||
return mPromise;
|
||||
}
|
||||
|
||||
virtual ~AsyncBlockers() {
|
||||
if (!mResolved) {
|
||||
mPromise->Resolve(true, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void MaybeResolve() {
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
if (mResolved) {
|
||||
return;
|
||||
}
|
||||
if (!mBlockers.empty()) {
|
||||
return;
|
||||
}
|
||||
mPromise->Resolve(true, __func__);
|
||||
mResolved = true;
|
||||
}
|
||||
Mutex mLock; // protects mBlockers and mResolved.
|
||||
std::map<void*, bool> mBlockers;
|
||||
bool mResolved = false;
|
||||
const RefPtr<GenericPromise::Private> mPromise;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_MediaUtils_h
|
||||
|
@ -88,7 +88,10 @@ GPUParent::GPUParent() : mLaunchTime(TimeStamp::Now()) { sGPUParent = this; }
|
||||
GPUParent::~GPUParent() { sGPUParent = nullptr; }
|
||||
|
||||
/* static */
|
||||
GPUParent* GPUParent::GetSingleton() { return sGPUParent; }
|
||||
GPUParent* GPUParent::GetSingleton() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(sGPUParent);
|
||||
return sGPUParent;
|
||||
}
|
||||
|
||||
bool GPUParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
||||
MessageLoop* aIOLoop, UniquePtr<IPC::Channel> aChannel) {
|
||||
@ -531,72 +534,80 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
ProcessChild::QuickExit();
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
wmf::MFShutdown();
|
||||
#endif
|
||||
|
||||
#ifndef NS_FREE_PERMANENT_DATA
|
||||
# ifdef XP_WIN
|
||||
wmf::MFShutdown();
|
||||
# endif
|
||||
// No point in going through XPCOM shutdown because we don't keep persistent
|
||||
// state.
|
||||
ProcessChild::QuickExit();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (mProfilerController) {
|
||||
mProfilerController->Shutdown();
|
||||
mProfilerController = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mVsyncBridge) {
|
||||
mVsyncBridge->Shutdown();
|
||||
mVsyncBridge = nullptr;
|
||||
}
|
||||
RemoteDecoderManagerParent::ShutdownVideoBridge();
|
||||
CompositorThreadHolder::Shutdown();
|
||||
// There is a case that RenderThread exists when gfxVars::UseWebRender() is
|
||||
// false. This could happen when WebRender was fallbacked to compositor.
|
||||
if (wr::RenderThread::Get()) {
|
||||
wr::RenderThread::ShutDown();
|
||||
}
|
||||
// Wait until all RemoteDecoderManagerParent have closed.
|
||||
mShutdownBlockers.WaitUntilClear(10 * 1000 /* 10s timeout*/)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__, [this]() {
|
||||
#ifdef XP_WIN
|
||||
if (widget::WinCompositorWindowThread::Get()) {
|
||||
widget::WinCompositorWindowThread::ShutDown();
|
||||
}
|
||||
wmf::MFShutdown();
|
||||
#endif
|
||||
|
||||
image::ImageMemoryReporter::ShutdownForWebRender();
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (mProfilerController) {
|
||||
mProfilerController->Shutdown();
|
||||
mProfilerController = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Shut down the default GL context provider.
|
||||
gl::GLContextProvider::Shutdown();
|
||||
if (mVsyncBridge) {
|
||||
mVsyncBridge->Shutdown();
|
||||
mVsyncBridge = nullptr;
|
||||
}
|
||||
RemoteDecoderManagerParent::ShutdownVideoBridge();
|
||||
CompositorThreadHolder::Shutdown();
|
||||
// There is a case that RenderThread exists when gfxVars::UseWebRender()
|
||||
// is false. This could happen when WebRender was fallbacked to
|
||||
// compositor.
|
||||
if (wr::RenderThread::Get()) {
|
||||
wr::RenderThread::ShutDown();
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
if (widget::WinCompositorWindowThread::Get()) {
|
||||
widget::WinCompositorWindowThread::ShutDown();
|
||||
}
|
||||
#endif
|
||||
|
||||
image::ImageMemoryReporter::ShutdownForWebRender();
|
||||
|
||||
// Shut down the default GL context provider.
|
||||
gl::GLContextProvider::Shutdown();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// The above shutdown calls operate on the available context providers on
|
||||
// most platforms. Windows is a "special snowflake", though, and has three
|
||||
// context providers available, so we have to shut all of them down.
|
||||
// We should only support the default GL provider on Windows; then, this
|
||||
// could go away. Unfortunately, we currently support WGL (the default) for
|
||||
// WebGL on Optimus.
|
||||
gl::GLContextProviderEGL::Shutdown();
|
||||
// The above shutdown calls operate on the available context providers
|
||||
// on most platforms. Windows is a "special snowflake", though, and has
|
||||
// three context providers available, so we have to shut all of them
|
||||
// down. We should only support the default GL provider on Windows;
|
||||
// then, this could go away. Unfortunately, we currently support WGL
|
||||
// (the default) for WebGL on Optimus.
|
||||
gl::GLContextProviderEGL::Shutdown();
|
||||
#endif
|
||||
|
||||
Factory::ShutDown();
|
||||
Factory::ShutDown();
|
||||
|
||||
// We bypass gfxPlatform shutdown, so we must shutdown any libraries here
|
||||
// that would normally be handled by it.
|
||||
// We bypass gfxPlatform shutdown, so we must shutdown any libraries here
|
||||
// that would normally be handled by it.
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
SkGraphics::PurgeFontCache();
|
||||
cairo_debug_reset_static_data();
|
||||
SkGraphics::PurgeFontCache();
|
||||
cairo_debug_reset_static_data();
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
DeviceManagerDx::Shutdown();
|
||||
DeviceManagerDx::Shutdown();
|
||||
#endif
|
||||
LayerTreeOwnerTracker::Shutdown();
|
||||
gfxVars::Shutdown();
|
||||
gfxConfig::Shutdown();
|
||||
CrashReporterClient::DestroySingleton();
|
||||
XRE_ShutdownChildProcess();
|
||||
LayerTreeOwnerTracker::Shutdown();
|
||||
gfxVars::Shutdown();
|
||||
gfxConfig::Shutdown();
|
||||
CrashReporterClient::DestroySingleton();
|
||||
XRE_ShutdownChildProcess();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mozilla::gfx
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/gfx/PGPUParent.h"
|
||||
#include "mozilla/media/MediaUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -25,6 +26,8 @@ class GPUParent final : public PGPUParent {
|
||||
|
||||
static GPUParent* GetSingleton();
|
||||
|
||||
AsyncBlockers& AsyncShutdownService() { return mShutdownBlockers; }
|
||||
|
||||
// Gets the name of the GPU process, in the format expected by about:memory.
|
||||
// There must be a GPU process active, and the caller must be either in that
|
||||
// process or the parent process.
|
||||
@ -99,6 +102,7 @@ class GPUParent final : public PGPUParent {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
RefPtr<ChildProfilerController> mProfilerController;
|
||||
#endif
|
||||
AsyncBlockers mShutdownBlockers;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
Loading…
Reference in New Issue
Block a user