mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-04 07:40:42 +00:00

In order to enable asynchronous launch, destruction of GeckoChildProcessHost (and its subclasses) has to be delayed until after launching (or anything else that might be made asynchronous in the future) has completed, to prevent use-after-free. However, there are other dependencies on process hosts always being destroyed on the I/O thread, so refcounting would be difficult to use. Instead, GeckoChildProcessHost now may not be destroyed directly, but must go through a method that handles the scheduling. There are also some minor cleanups to the affected headers (removed duplicate access modifiers, and made PluginProcessParent final). Depends on D18010 Differential Revision: https://phabricator.services.mozilla.com/D18011 --HG-- extra : moz-landing-system : lando
227 lines
6.1 KiB
C++
227 lines
6.1 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
#include "TestEndpointBridgeMain.h"
|
|
|
|
#include "base/task.h"
|
|
#include "IPDLUnitTests.h" // fail etc.
|
|
#include "IPDLUnitTestSubprocess.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace mozilla {
|
|
namespace _ipdltest {
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// main process
|
|
void TestEndpointBridgeMainParent::Main() {
|
|
if (!SendStart()) {
|
|
fail("sending Start");
|
|
}
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainParent::RecvBridged(
|
|
Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint) {
|
|
TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent();
|
|
if (!endpoint.Bind(a)) {
|
|
fail("Bind failed");
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
passed("ok");
|
|
QuitParent();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHello() {
|
|
if (!SendHi()) {
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHelloSync() {
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::AnswerHelloRpc() {
|
|
if (!CallHiRpc()) {
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
|
|
// ActorDestroy() is just a callback from IPDL-generated code,
|
|
// which needs the top-level actor (this) to stay alive a little
|
|
// longer so other things can be cleaned up.
|
|
MessageLoop::current()->PostTask(
|
|
do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this)));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// sub process --- child of main
|
|
TestEndpointBridgeMainChild* gEndpointBridgeMainChild;
|
|
|
|
TestEndpointBridgeMainChild::TestEndpointBridgeMainChild()
|
|
: mSubprocess(nullptr) {
|
|
gEndpointBridgeMainChild = this;
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainChild::RecvStart() {
|
|
vector<string> subsubArgs;
|
|
subsubArgs.push_back("TestEndpointBridgeSub");
|
|
|
|
mSubprocess = new IPDLUnitTestSubprocess();
|
|
if (!mSubprocess->SyncLaunch(subsubArgs)) {
|
|
fail("problem launching subprocess");
|
|
}
|
|
|
|
IPC::Channel* transport = mSubprocess->GetChannel();
|
|
if (!transport) {
|
|
fail("no transport");
|
|
}
|
|
|
|
TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent();
|
|
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
|
|
|
|
bsp->Main();
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
// NB: this is kosher because QuitChild() joins with the IO thread
|
|
mSubprocess->Destroy();
|
|
mSubprocess = nullptr;
|
|
QuitChild();
|
|
}
|
|
|
|
void TestEndpointBridgeSubParent::Main() {
|
|
if (!SendPing()) {
|
|
fail("sending Ping");
|
|
}
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeSubParent::RecvBridgeEm() {
|
|
Endpoint<PTestEndpointBridgeMainSubParent> parent;
|
|
Endpoint<PTestEndpointBridgeMainSubChild> child;
|
|
nsresult rv;
|
|
rv = PTestEndpointBridgeMainSub::CreateEndpoints(
|
|
gEndpointBridgeMainChild->OtherPid(), OtherPid(), &parent, &child);
|
|
if (NS_FAILED(rv)) {
|
|
fail("opening PTestEndpointOpensOpened");
|
|
}
|
|
|
|
if (!gEndpointBridgeMainChild->SendBridged(std::move(parent))) {
|
|
fail("SendBridge failed for parent");
|
|
}
|
|
if (!SendBridged(std::move(child))) {
|
|
fail("SendBridge failed for child");
|
|
}
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
gEndpointBridgeMainChild->Close();
|
|
|
|
// ActorDestroy() is just a callback from IPDL-generated code,
|
|
// which needs the top-level actor (this) to stay alive a little
|
|
// longer so other things can be cleaned up.
|
|
MessageLoop::current()->PostTask(
|
|
do_AddRef(new DeleteTask<TestEndpointBridgeSubParent>(this)));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// subsub process --- child of sub
|
|
|
|
static TestEndpointBridgeSubChild* gBridgeSubChild;
|
|
|
|
TestEndpointBridgeSubChild::TestEndpointBridgeSubChild() {
|
|
gBridgeSubChild = this;
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvPing() {
|
|
if (!SendBridgeEm()) {
|
|
fail("sending BridgeEm");
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvBridged(
|
|
Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint) {
|
|
TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild();
|
|
|
|
if (!endpoint.Bind(a)) {
|
|
fail("failed to Bind");
|
|
}
|
|
|
|
if (!a->SendHello()) {
|
|
fail("sending Hello");
|
|
}
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
QuitChild();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::RecvHi() {
|
|
if (!SendHelloSync()) {
|
|
fail("sending HelloSync");
|
|
}
|
|
if (!CallHelloRpc()) {
|
|
fail("calling HelloRpc");
|
|
}
|
|
if (!mGotHi) {
|
|
fail("didn't answer HiRpc");
|
|
}
|
|
|
|
// Need to close the channel without message-processing frames on
|
|
// the C++ stack
|
|
MessageLoop::current()->PostTask(
|
|
NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this,
|
|
&TestEndpointBridgeMainSubChild::Close));
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::AnswerHiRpc() {
|
|
mGotHi = true; // d00d
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) {
|
|
if (NormalShutdown != why) {
|
|
fail("unexpected destruction!");
|
|
}
|
|
|
|
gBridgeSubChild->Close();
|
|
|
|
// ActorDestroy() is just a callback from IPDL-generated code,
|
|
// which needs the top-level actor (this) to stay alive a little
|
|
// longer so other things can be cleaned up.
|
|
MessageLoop::current()->PostTask(
|
|
do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this)));
|
|
}
|
|
|
|
} // namespace _ipdltest
|
|
} // namespace mozilla
|