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
112 lines
3.2 KiB
C++
112 lines
3.2 KiB
C++
#include "TestInterruptShutdownRace.h"
|
|
|
|
#include "base/task.h"
|
|
#include "IPDLUnitTests.h" // fail etc.
|
|
#include "IPDLUnitTestSubprocess.h"
|
|
|
|
namespace mozilla {
|
|
namespace _ipdltest {
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// parent
|
|
|
|
namespace {
|
|
|
|
// NB: this test does its own shutdown, rather than going through
|
|
// QuitParent(), because it's testing degenerate edge cases
|
|
|
|
void DeleteSubprocess() {
|
|
gSubprocess->Destroy();
|
|
gSubprocess = nullptr;
|
|
}
|
|
|
|
void Done() {
|
|
passed(__FILE__);
|
|
QuitParent();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent() {
|
|
MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent);
|
|
}
|
|
|
|
TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent() {
|
|
MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent);
|
|
}
|
|
|
|
void TestInterruptShutdownRaceParent::Main() {
|
|
if (!SendStart()) fail("sending Start");
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvStartDeath() {
|
|
// this will be ordered before the OnMaybeDequeueOne event of
|
|
// Orphan in the queue
|
|
MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
|
|
"_ipdltest::TestInterruptShutdownRaceParent::StartShuttingDown", this,
|
|
&TestInterruptShutdownRaceParent::StartShuttingDown));
|
|
return IPC_OK();
|
|
}
|
|
|
|
void TestInterruptShutdownRaceParent::StartShuttingDown() {
|
|
// NB: we sleep here to try and avoid receiving the Orphan message
|
|
// while waiting for the CallExit() reply. if we fail at that, it
|
|
// will cause the test to pass spuriously, because there won't be
|
|
// an OnMaybeDequeueOne task for Orphan
|
|
PR_Sleep(2000);
|
|
|
|
if (CallExit()) fail("connection was supposed to be interrupted");
|
|
|
|
Close();
|
|
|
|
delete static_cast<TestInterruptShutdownRaceParent*>(gParentActor);
|
|
gParentActor = nullptr;
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
NewRunnableFunction("DeleteSubprocess", DeleteSubprocess));
|
|
|
|
// this is ordered after the OnMaybeDequeueOne event in the queue
|
|
MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done));
|
|
|
|
// |this| has been deleted, be mindful
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvOrphan() {
|
|
// it would be nice to fail() here, but we'll process this message
|
|
// while waiting for the reply CallExit(). The OnMaybeDequeueOne
|
|
// task will still be in the queue, it just wouldn't have had any
|
|
// work to do, if we hadn't deleted ourself
|
|
return IPC_OK();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// child
|
|
|
|
TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild() {
|
|
MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild);
|
|
}
|
|
|
|
TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild() {
|
|
MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild);
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::RecvStart() {
|
|
if (!SendStartDeath()) fail("sending StartDeath");
|
|
|
|
// See comment in StartShuttingDown(): we want to send Orphan()
|
|
// while the parent is in its PR_Sleep()
|
|
PR_Sleep(1000);
|
|
|
|
if (!SendOrphan()) fail("sending Orphan");
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::AnswerExit() {
|
|
_exit(0);
|
|
MOZ_CRASH("unreached");
|
|
}
|
|
|
|
} // namespace _ipdltest
|
|
} // namespace mozilla
|