gecko-dev/ipc/ipdl/test/cxx/TestOpens.cpp

252 lines
6.0 KiB
C++

#include "base/task.h"
#include "base/thread.h"
#include "TestOpens.h"
#include "IPDLUnitTests.h" // fail etc.
using namespace mozilla::ipc;
using base::ProcessHandle;
using base::Thread;
namespace mozilla {
// NB: this is generally bad style, but I am lazy.
using namespace _ipdltest;
using namespace _ipdltest2;
static MessageLoop* gMainThread;
static void
AssertNotMainThread()
{
if (!gMainThread)
fail("gMainThread is not initialized");
if (MessageLoop::current() == gMainThread)
fail("unexpectedly called on the main thread");
}
//-----------------------------------------------------------------------------
// parent
// Thread on which TestOpensOpenedParent runs
static Thread* gParentThread;
void
TestOpensParent::Main()
{
if (!SendStart())
fail("sending Start");
}
static void
OpenParent(TestOpensOpenedParent* aParent,
Transport* aTransport, base::ProcessId aOtherPid)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aParent->Open(aTransport, aOtherPid,
XRE_GetIOMessageLoop(), ipc::ParentSide))
fail("opening Parent");
}
PTestOpensOpenedParent*
TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport,
ProcessId otherPid)
{
gMainThread = MessageLoop::current();
gParentThread = new Thread("ParentThread");
if (!gParentThread->Start())
fail("starting parent thread");
TestOpensOpenedParent* a = new TestOpensOpenedParent(transport);
gParentThread->message_loop()->PostTask(
NewRunnableFunction(OpenParent, a, transport, otherPid));
return a;
}
void
TestOpensParent::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gParentThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
bool
TestOpensOpenedParent::RecvHello()
{
AssertNotMainThread();
return SendHi();
}
bool
TestOpensOpenedParent::RecvHelloSync()
{
AssertNotMainThread();
return true;
}
bool
TestOpensOpenedParent::AnswerHelloRpc()
{
AssertNotMainThread();
return CallHiRpc();
}
static void
ShutdownTestOpensOpenedParent(TestOpensOpenedParent* parent,
Transport* transport)
{
delete parent;
}
void
TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
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.
gParentThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestOpensOpenedParent,
this, mTransport));
}
//-----------------------------------------------------------------------------
// child
static TestOpensChild* gOpensChild;
// Thread on which TestOpensOpenedChild runs
static Thread* gChildThread;
TestOpensChild::TestOpensChild()
{
gOpensChild = this;
}
bool
TestOpensChild::RecvStart()
{
if (!PTestOpensOpened::Open(this))
fail("opening PTestOpensOpened");
return true;
}
static void
OpenChild(TestOpensOpenedChild* aChild,
Transport* aTransport, base::ProcessId aOtherPid)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aChild->Open(aTransport, aOtherPid,
XRE_GetIOMessageLoop(), ipc::ChildSide))
fail("opening Child");
// Kick off the unit tests
if (!aChild->SendHello())
fail("sending Hello");
}
PTestOpensOpenedChild*
TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport,
ProcessId otherPid)
{
gMainThread = MessageLoop::current();
gChildThread = new Thread("ChildThread");
if (!gChildThread->Start())
fail("starting child thread");
TestOpensOpenedChild* a = new TestOpensOpenedChild(transport);
gChildThread->message_loop()->PostTask(
NewRunnableFunction(OpenChild, a, transport, otherPid));
return a;
}
void
TestOpensChild::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gChildThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
bool
TestOpensOpenedChild::RecvHi()
{
AssertNotMainThread();
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(this, &TestOpensOpenedChild::Close));
return true;
}
bool
TestOpensOpenedChild::AnswerHiRpc()
{
AssertNotMainThread();
mGotHi = true; // d00d
return true;
}
static void
ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child,
Transport* transport)
{
delete child;
// Kick off main-thread shutdown.
gMainThread->PostTask(
NewNonOwningRunnableMethod(gOpensChild, &TestOpensChild::Close));
}
void
TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
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. Defer shutdown to
// let cleanup finish.
gChildThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestOpensOpenedChild,
this, mTransport));
}
} // namespace mozilla