diff --git a/ipc/ipdl/test/cxx/PTestOpens.ipdl b/ipc/ipdl/test/cxx/PTestOpens.ipdl index d3a7bcafb13..f0562d22eec 100644 --- a/ipc/ipdl/test/cxx/PTestOpens.ipdl +++ b/ipc/ipdl/test/cxx/PTestOpens.ipdl @@ -5,6 +5,7 @@ namespace _ipdltest { protocol PTestOpens { + // This channel is opened and parked on a non-main thread child opens PTestOpensOpened; child: diff --git a/ipc/ipdl/test/cxx/TestOpens.cpp b/ipc/ipdl/test/cxx/TestOpens.cpp index 1703dffff01..4b17b42c768 100644 --- a/ipc/ipdl/test/cxx/TestOpens.cpp +++ b/ipc/ipdl/test/cxx/TestOpens.cpp @@ -1,7 +1,16 @@ +#include "base/thread.h" + #include "TestOpens.h" #include "IPDLUnitTests.h" // fail etc. +template<> +struct RunnableMethodTraits +{ + static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { } + static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { } +}; + template<> struct RunnableMethodTraits { @@ -9,12 +18,29 @@ struct RunnableMethodTraits static void ReleaseCallee(mozilla::_ipdltest::TestOpensOpenedChild* obj) { } }; +using namespace base; +using namespace mozilla::ipc; + namespace mozilla { namespace _ipdltest { +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() { @@ -22,25 +48,49 @@ TestOpensParent::Main() fail("sending Start"); } +static void +OpenParent(TestOpensOpenedParent* aParent, + Transport* aTransport, ProcessHandle aOtherProcess) +{ + 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, aOtherProcess, + XRE_GetIOMessageLoop(), AsyncChannel::Parent)) + fail("opening Parent"); +} + PTestOpensOpenedParent* TestOpensParent::AllocPTestOpensOpened(Transport* transport, ProcessId otherProcess) { + gMainThread = MessageLoop::current(); + ProcessHandle h; if (!base::OpenProcessHandle(otherProcess, &h)) { return nsnull; } - nsAutoPtr a(new TestOpensOpenedParent(transport)); - if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Parent)) { - return nsnull; - } - return a.forget(); + gParentThread = new Thread("ParentThread"); + if (!gParentThread->Start()) + fail("starting parent thread"); + + TestOpensOpenedParent* a = new TestOpensOpenedParent(transport); + gParentThread->message_loop()->PostTask( + FROM_HERE, + NewRunnableFunction(OpenParent, a, transport, h)); + + return a; } void TestOpensParent::ActorDestroy(ActorDestroyReason why) { + // Stops the thread and joins it + delete gParentThread; + if (NormalShutdown != why) fail("unexpected destruction!"); passed("ok"); @@ -50,24 +100,29 @@ TestOpensParent::ActorDestroy(ActorDestroyReason why) bool TestOpensOpenedParent::RecvHello() { + AssertNotMainThread(); return SendHi(); } bool TestOpensOpenedParent::RecvHelloSync() { + AssertNotMainThread(); return true; } bool TestOpensOpenedParent::AnswerHelloRpc() { + AssertNotMainThread(); return CallHiRpc(); } void TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why) { + AssertNotMainThread(); + if (NormalShutdown != why) fail("unexpected destruction!"); @@ -86,6 +141,8 @@ TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why) // child static TestOpensChild* gOpensChild; +// Thread on which TestOpensOpenedChild runs +static Thread* gChildThread; TestOpensChild::TestOpensChild() { @@ -100,29 +157,53 @@ TestOpensChild::RecvStart() return true; } +static void +OpenChild(TestOpensOpenedChild* aChild, + Transport* aTransport, ProcessHandle aOtherProcess) +{ + 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, aOtherProcess, + XRE_GetIOMessageLoop(), AsyncChannel::Child)) + fail("opening Child"); + + // Kick off the unit tests + if (!aChild->SendHello()) + fail("sending Hello"); +} + PTestOpensOpenedChild* TestOpensChild::AllocPTestOpensOpened(Transport* transport, ProcessId otherProcess) { + gMainThread = MessageLoop::current(); + ProcessHandle h; if (!base::OpenProcessHandle(otherProcess, &h)) { return nsnull; } - nsAutoPtr a(new TestOpensOpenedChild(transport)); - if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Child)) { - return nsnull; - } + gChildThread = new Thread("ChildThread"); + if (!gChildThread->Start()) + fail("starting child thread"); - if (!a->SendHello()) - fail("sending Hello"); + TestOpensOpenedChild* a = new TestOpensOpenedChild(transport); + gChildThread->message_loop()->PostTask( + FROM_HERE, + NewRunnableFunction(OpenChild, a, transport, h)); - return a.forget(); + return a; } void TestOpensChild::ActorDestroy(ActorDestroyReason why) { + // Stops the thread and joins it + delete gChildThread; + if (NormalShutdown != why) fail("unexpected destruction!"); QuitChild(); @@ -131,6 +212,8 @@ TestOpensChild::ActorDestroy(ActorDestroyReason why) bool TestOpensOpenedChild::RecvHi() { + AssertNotMainThread(); + if (!SendHelloSync()) fail("sending HelloSync"); if (!CallHelloRpc()) @@ -149,6 +232,8 @@ TestOpensOpenedChild::RecvHi() bool TestOpensOpenedChild::AnswerHiRpc() { + AssertNotMainThread(); + mGotHi = true; // d00d return true; } @@ -156,11 +241,11 @@ TestOpensOpenedChild::AnswerHiRpc() void TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) { + AssertNotMainThread(); + if (NormalShutdown != why) fail("unexpected destruction!"); - gOpensChild->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. @@ -170,6 +255,11 @@ TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) XRE_GetIOMessageLoop()->PostTask( FROM_HERE, new DeleteTask(mTransport)); + + // Kick off main-thread shutdown. + gMainThread->PostTask( + FROM_HERE, + NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); } } // namespace _ipdltest