diff options
Diffstat (limited to 'ipc/ipdl/test/cxx/TestOpens.cpp')
-rw-r--r-- | ipc/ipdl/test/cxx/TestOpens.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/TestOpens.cpp b/ipc/ipdl/test/cxx/TestOpens.cpp new file mode 100644 index 000000000..cb1ed00b5 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestOpens.cpp @@ -0,0 +1,251 @@ +#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 |