michael@0: #include "TestBridgeMain.h" michael@0: michael@0: #include "IPDLUnitTests.h" // fail etc. michael@0: #include "IPDLUnitTestSubprocess.h" michael@0: michael@0: using namespace std; michael@0: michael@0: template<> michael@0: struct RunnableMethodTraits michael@0: { michael@0: static void RetainCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { } michael@0: static void ReleaseCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { } michael@0: }; michael@0: michael@0: namespace mozilla { michael@0: namespace _ipdltest { michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // main process michael@0: void michael@0: TestBridgeMainParent::Main() michael@0: { michael@0: if (!SendStart()) michael@0: fail("sending Start"); michael@0: } michael@0: michael@0: PTestBridgeMainSubParent* michael@0: TestBridgeMainParent::AllocPTestBridgeMainSubParent(Transport* transport, michael@0: ProcessId otherProcess) michael@0: { michael@0: ProcessHandle h; michael@0: if (!base::OpenProcessHandle(otherProcess, &h)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsAutoPtr a(new TestBridgeMainSubParent(transport)); michael@0: if (!a->Open(transport, h, XRE_GetIOMessageLoop(), ipc::ParentSide)) { michael@0: return nullptr; michael@0: } michael@0: return a.forget(); michael@0: } michael@0: michael@0: void michael@0: TestBridgeMainParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: passed("ok"); michael@0: QuitParent(); michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainSubParent::RecvHello() michael@0: { michael@0: return SendHi(); michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainSubParent::RecvHelloSync() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainSubParent::AnswerHelloRpc() michael@0: { michael@0: return CallHiRpc(); michael@0: } michael@0: michael@0: void michael@0: TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: michael@0: // ActorDestroy() is just a callback from IPDL-generated code, michael@0: // which needs the top-level actor (this) to stay alive a little michael@0: // longer so other things can be cleaned up. michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(this)); michael@0: XRE_GetIOMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(mTransport)); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // sub process --- child of main michael@0: TestBridgeMainChild* gBridgeMainChild; michael@0: michael@0: TestBridgeMainChild::TestBridgeMainChild() michael@0: : mSubprocess(nullptr) michael@0: { michael@0: gBridgeMainChild = this; michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainChild::RecvStart() michael@0: { michael@0: vector subsubArgs; michael@0: subsubArgs.push_back("TestBridgeSub"); michael@0: michael@0: mSubprocess = new IPDLUnitTestSubprocess(); michael@0: if (!mSubprocess->SyncLaunch(subsubArgs)) michael@0: fail("problem launching subprocess"); michael@0: michael@0: IPC::Channel* transport = mSubprocess->GetChannel(); michael@0: if (!transport) michael@0: fail("no transport"); michael@0: michael@0: TestBridgeSubParent* bsp = new TestBridgeSubParent(); michael@0: bsp->Open(transport, mSubprocess->GetChildProcessHandle()); michael@0: michael@0: bsp->Main(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TestBridgeMainChild::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: // NB: this is kosher because QuitChild() joins with the IO thread michael@0: XRE_GetIOMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(mSubprocess)); michael@0: QuitChild(); michael@0: } michael@0: michael@0: void michael@0: TestBridgeSubParent::Main() michael@0: { michael@0: if (!SendPing()) michael@0: fail("sending Ping"); michael@0: } michael@0: michael@0: bool michael@0: TestBridgeSubParent::RecvBridgeEm() michael@0: { michael@0: if (!PTestBridgeMainSub::Bridge(gBridgeMainChild, this)) michael@0: fail("bridging Main and Sub"); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TestBridgeSubParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: gBridgeMainChild->Close(); michael@0: michael@0: // ActorDestroy() is just a callback from IPDL-generated code, michael@0: // which needs the top-level actor (this) to stay alive a little michael@0: // longer so other things can be cleaned up. michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(this)); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // subsub process --- child of sub michael@0: michael@0: static TestBridgeSubChild* gBridgeSubChild; michael@0: michael@0: TestBridgeSubChild::TestBridgeSubChild() michael@0: { michael@0: gBridgeSubChild = this; michael@0: } michael@0: michael@0: bool michael@0: TestBridgeSubChild::RecvPing() michael@0: { michael@0: if (!SendBridgeEm()) michael@0: fail("sending BridgeEm"); michael@0: return true; michael@0: } michael@0: michael@0: PTestBridgeMainSubChild* michael@0: TestBridgeSubChild::AllocPTestBridgeMainSubChild(Transport* transport, michael@0: ProcessId otherProcess) michael@0: { michael@0: ProcessHandle h; michael@0: if (!base::OpenProcessHandle(otherProcess, &h)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsAutoPtr a(new TestBridgeMainSubChild(transport)); michael@0: if (!a->Open(transport, h, XRE_GetIOMessageLoop(), ipc::ChildSide)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!a->SendHello()) michael@0: fail("sending Hello"); michael@0: michael@0: return a.forget(); michael@0: } michael@0: michael@0: void michael@0: TestBridgeSubChild::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: QuitChild(); michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainSubChild::RecvHi() michael@0: { michael@0: if (!SendHelloSync()) michael@0: fail("sending HelloSync"); michael@0: if (!CallHelloRpc()) michael@0: fail("calling HelloRpc"); michael@0: if (!mGotHi) michael@0: fail("didn't answer HiRpc"); michael@0: michael@0: // Need to close the channel without message-processing frames on michael@0: // the C++ stack michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &TestBridgeMainSubChild::Close)); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TestBridgeMainSubChild::AnswerHiRpc() michael@0: { michael@0: mGotHi = true; // d00d michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (NormalShutdown != why) michael@0: fail("unexpected destruction!"); michael@0: michael@0: gBridgeSubChild->Close(); michael@0: michael@0: // ActorDestroy() is just a callback from IPDL-generated code, michael@0: // which needs the top-level actor (this) to stay alive a little michael@0: // longer so other things can be cleaned up. michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(this)); michael@0: XRE_GetIOMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: new DeleteTask(mTransport)); michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: } // namespace _ipdltest