Implement GPU process shutdown. (bug 1271180 part 5, r=billm)

--HG--
extra : rebase_source : 13e7c4274e3948e13096baf3bf4e48000d3f8864
This commit is contained in:
David Anderson 2016-06-10 22:37:03 -04:00
parent d3bb5cb316
commit ebb01e928a
9 changed files with 145 additions and 8 deletions

View File

@ -4,11 +4,13 @@
* 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 "GPUChild.h"
#include "GPUProcessHost.h"
namespace mozilla {
namespace gfx {
GPUChild::GPUChild()
GPUChild::GPUChild(GPUProcessHost* aHost)
: mHost(aHost)
{
MOZ_COUNT_CTOR(GPUChild);
}
@ -18,5 +20,33 @@ GPUChild::~GPUChild()
MOZ_COUNT_DTOR(GPUChild);
}
void
GPUChild::ActorDestroy(ActorDestroyReason aWhy)
{
mHost->OnChannelClosed();
}
class DeferredDeleteGPUChild : public Runnable
{
public:
explicit DeferredDeleteGPUChild(UniquePtr<GPUChild>&& aChild)
: mChild(Move(aChild))
{
}
NS_IMETHODIMP Run() override {
return NS_OK;
}
private:
UniquePtr<GPUChild> mChild;
};
/* static */ void
GPUChild::Destroy(UniquePtr<GPUChild>&& aChild)
{
NS_DispatchToMainThread(new DeferredDeleteGPUChild(Move(aChild)));
}
} // namespace gfx
} // namespace mozilla

View File

@ -7,15 +7,25 @@
#define _include_mozilla_gfx_ipc_GPUChild_h_
#include "mozilla/gfx/PGPUChild.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace gfx {
class GPUProcessHost;
class GPUChild final : public PGPUChild
{
public:
GPUChild();
explicit GPUChild(GPUProcessHost* aHost);
~GPUChild();
static void Destroy(UniquePtr<GPUChild>&& aChild);
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
GPUProcessHost* mHost;
};
} // namespace gfx

View File

@ -35,7 +35,7 @@ GPUParent::Init(base::ProcessId aParentPid,
}
bool
GPUParent::RecvBeginShutdown()
GPUParent::RecvNothing()
{
return true;
}
@ -48,7 +48,14 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
ProcessChild::QuickExit();
}
#ifndef NS_FREE_PERMANENT_DATA
// No point in going through XPCOM shutdown because we don't keep persistent
// state. Currently we quick-exit in RecvBeginShutdown so this should be
// unreachable.
ProcessChild::QuickExit();
#else
XRE_ShutdownChildProcess();
#endif
}
} // namespace gfx

View File

@ -21,7 +21,7 @@ public:
MessageLoop* aIOLoop,
IPC::Channel* aChannel);
bool RecvBeginShutdown() override;
bool RecvNothing() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
};

View File

@ -4,9 +4,11 @@
* 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 "gfxPrefs.h"
#include "GPUProcessHost.h"
#include "chrome/common/process_watcher.h"
#include "gfxPrefs.h"
#include "mozilla/gfx/Logging.h"
#include "nsITimer.h"
namespace mozilla {
namespace gfx {
@ -15,7 +17,8 @@ GPUProcessHost::GPUProcessHost(Listener* aListener)
: GeckoChildProcessHost(GeckoProcessType_GPU),
mListener(aListener),
mTaskFactory(this),
mLaunchPhase(LaunchPhase::Unlaunched)
mLaunchPhase(LaunchPhase::Unlaunched),
mShutdownRequested(false)
{
MOZ_COUNT_CTOR(GPUProcessHost);
}
@ -115,7 +118,7 @@ GPUProcessHost::InitAfterConnect(bool aSucceeded)
mLaunchPhase = LaunchPhase::Complete;
if (aSucceeded) {
mGPUChild = MakeUnique<GPUChild>();
mGPUChild = MakeUnique<GPUChild>(this);
DebugOnly<bool> rv =
mGPUChild->Open(GetChannel(), base::GetProcId(GetChildProcessHandle()));
MOZ_ASSERT(rv);
@ -129,10 +132,66 @@ GPUProcessHost::InitAfterConnect(bool aSucceeded)
void
GPUProcessHost::Shutdown()
{
MOZ_ASSERT(!mShutdownRequested);
mListener = nullptr;
if (mGPUChild) {
// OnChannelClosed uses this to check if the shutdown was expected or
// unexpected.
mShutdownRequested = true;
#ifdef NS_FREE_PERMANENT_DATA
mGPUChild->Close();
#else
// No need to communicate shutdown, the GPU process doesn't need to
// communicate anything back.
KillHard("NormalShutdown");
#endif
// Wait for ActorDestroy.
return;
}
DestroyProcess();
}
void
GPUProcessHost::OnChannelClosed()
{
if (!mShutdownRequested) {
// This is an unclean shutdown. Notify our listener that we're going away.
if (mListener) {
mListener->OnProcessUnexpectedShutdown(this);
}
}
// Release the actor.
GPUChild::Destroy(Move(mGPUChild));
MOZ_ASSERT(!mGPUChild);
// If the owner of GPUProcessHost already requested shutdown, we can now
// schedule destruction. Otherwise we must wait for someone to call
// Shutdown. Note that GPUProcessManager calls Shutdown within
// OnProcessUnexpectedShutdown.
if (mShutdownRequested) {
DestroyProcess();
}
}
void
GPUProcessHost::KillHard(const char* aReason)
{
ProcessHandle handle = GetChildProcessHandle();
if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER, false)) {
NS_WARNING("failed to kill subprocess!");
}
SetAlreadyDead();
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated, handle, /*force=*/true));
}
void
GPUProcessHost::DestroyProcess()
{

View File

@ -11,8 +11,11 @@
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/TaskFactory.h"
class nsITimer;
namespace mozilla {
namespace gfx {
@ -27,11 +30,19 @@ class GPUChild;
// at a time due to its shutdown being asynchronous.
class GPUProcessHost final : public ipc::GeckoChildProcessHost
{
friend class GPUChild;
public:
class Listener {
public:
virtual void OnProcessLaunchComplete(GPUProcessHost* aHost)
{}
// The GPUProcessHost has unexpectedly shutdown or had its connection
// severed. This is not called if an error occurs after calling
// Shutdown().
virtual void OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
{}
};
public:
@ -71,6 +82,8 @@ public:
void OnChannelConnected(int32_t peer_pid) override;
void OnChannelError() override;
void SetListener(Listener* aListener);
private:
// Called on the main thread.
void OnChannelConnectedTask();
@ -79,6 +92,12 @@ private:
// Called on the main thread after a connection has been established.
void InitAfterConnect(bool aSucceeded);
// Called on the main thread when the mGPUChild actor is shutting down.
void OnChannelClosed();
// Kill the remote process, triggering IPC shutdown.
void KillHard(const char* aReason);
void DestroyProcess();
private:
@ -95,6 +114,9 @@ private:
LaunchPhase mLaunchPhase;
UniquePtr<GPUChild> mGPUChild;
Listener* listener_;
bool mShutdownRequested;
};
} // namespace gfx

View File

@ -129,6 +129,14 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
mGPUChild = mProcess->GetActor();
}
void
GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
{
MOZ_ASSERT(mProcess && mProcess == aHost);
DestroyProcess();
}
void
GPUProcessManager::DestroyProcess()
{

View File

@ -105,6 +105,7 @@ public:
dom::TabParent* aBrowserParent);
void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
private:
// Called from our xpcom-shutdown observer.

View File

@ -10,7 +10,7 @@ sync protocol PGPU
{
parent:
// Sent by the UI process to initiate shutdown.
async BeginShutdown();
async Nothing();
};
} // namespace gfx