1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/ipdl/test/cxx/TestOpens.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,279 @@ 1.4 +#include "base/thread.h" 1.5 + 1.6 +#include "TestOpens.h" 1.7 + 1.8 +#include "IPDLUnitTests.h" // fail etc. 1.9 + 1.10 +template<> 1.11 +struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensChild> 1.12 +{ 1.13 + static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { } 1.14 + static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { } 1.15 +}; 1.16 + 1.17 +template<> 1.18 +struct RunnableMethodTraits<mozilla::_ipdltest2::TestOpensOpenedChild> 1.19 +{ 1.20 + static void RetainCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { } 1.21 + static void ReleaseCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { } 1.22 +}; 1.23 + 1.24 +using namespace base; 1.25 +using namespace mozilla::ipc; 1.26 + 1.27 +namespace mozilla { 1.28 +// NB: this is generally bad style, but I am lazy. 1.29 +using namespace _ipdltest; 1.30 +using namespace _ipdltest2; 1.31 + 1.32 +static MessageLoop* gMainThread; 1.33 + 1.34 +static void 1.35 +AssertNotMainThread() 1.36 +{ 1.37 + if (!gMainThread) 1.38 + fail("gMainThread is not initialized"); 1.39 + if (MessageLoop::current() == gMainThread) 1.40 + fail("unexpectedly called on the main thread"); 1.41 +} 1.42 + 1.43 +//----------------------------------------------------------------------------- 1.44 +// parent 1.45 + 1.46 +// Thread on which TestOpensOpenedParent runs 1.47 +static Thread* gParentThread; 1.48 + 1.49 +void 1.50 +TestOpensParent::Main() 1.51 +{ 1.52 + if (!SendStart()) 1.53 + fail("sending Start"); 1.54 +} 1.55 + 1.56 +static void 1.57 +OpenParent(TestOpensOpenedParent* aParent, 1.58 + Transport* aTransport, ProcessHandle aOtherProcess) 1.59 +{ 1.60 + AssertNotMainThread(); 1.61 + 1.62 + // Open the actor on the off-main thread to park it there. 1.63 + // Messages will be delivered to this thread's message loop 1.64 + // instead of the main thread's. 1.65 + if (!aParent->Open(aTransport, aOtherProcess, 1.66 + XRE_GetIOMessageLoop(), ipc::ParentSide)) 1.67 + fail("opening Parent"); 1.68 +} 1.69 + 1.70 +PTestOpensOpenedParent* 1.71 +TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport, 1.72 + ProcessId otherProcess) 1.73 +{ 1.74 + gMainThread = MessageLoop::current(); 1.75 + 1.76 + ProcessHandle h; 1.77 + if (!base::OpenProcessHandle(otherProcess, &h)) { 1.78 + return nullptr; 1.79 + } 1.80 + 1.81 + gParentThread = new Thread("ParentThread"); 1.82 + if (!gParentThread->Start()) 1.83 + fail("starting parent thread"); 1.84 + 1.85 + TestOpensOpenedParent* a = new TestOpensOpenedParent(transport); 1.86 + gParentThread->message_loop()->PostTask( 1.87 + FROM_HERE, 1.88 + NewRunnableFunction(OpenParent, a, transport, h)); 1.89 + 1.90 + return a; 1.91 +} 1.92 + 1.93 +void 1.94 +TestOpensParent::ActorDestroy(ActorDestroyReason why) 1.95 +{ 1.96 + // Stops the thread and joins it 1.97 + delete gParentThread; 1.98 + 1.99 + if (NormalShutdown != why) 1.100 + fail("unexpected destruction!"); 1.101 + passed("ok"); 1.102 + QuitParent(); 1.103 +} 1.104 + 1.105 +bool 1.106 +TestOpensOpenedParent::RecvHello() 1.107 +{ 1.108 + AssertNotMainThread(); 1.109 + return SendHi(); 1.110 +} 1.111 + 1.112 +bool 1.113 +TestOpensOpenedParent::RecvHelloSync() 1.114 +{ 1.115 + AssertNotMainThread(); 1.116 + return true; 1.117 +} 1.118 + 1.119 +bool 1.120 +TestOpensOpenedParent::AnswerHelloRpc() 1.121 +{ 1.122 + AssertNotMainThread(); 1.123 + return CallHiRpc(); 1.124 +} 1.125 + 1.126 +void 1.127 +TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why) 1.128 +{ 1.129 + AssertNotMainThread(); 1.130 + 1.131 + if (NormalShutdown != why) 1.132 + fail("unexpected destruction!"); 1.133 + 1.134 + // ActorDestroy() is just a callback from IPDL-generated code, 1.135 + // which needs the top-level actor (this) to stay alive a little 1.136 + // longer so other things can be cleaned up. 1.137 + MessageLoop::current()->PostTask( 1.138 + FROM_HERE, 1.139 + new DeleteTask<TestOpensOpenedParent>(this)); 1.140 + XRE_GetIOMessageLoop()->PostTask( 1.141 + FROM_HERE, 1.142 + new DeleteTask<Transport>(mTransport)); 1.143 +} 1.144 + 1.145 +//----------------------------------------------------------------------------- 1.146 +// child 1.147 + 1.148 +static TestOpensChild* gOpensChild; 1.149 +// Thread on which TestOpensOpenedChild runs 1.150 +static Thread* gChildThread; 1.151 + 1.152 +TestOpensChild::TestOpensChild() 1.153 +{ 1.154 + gOpensChild = this; 1.155 +} 1.156 + 1.157 +bool 1.158 +TestOpensChild::RecvStart() 1.159 +{ 1.160 + if (!PTestOpensOpened::Open(this)) 1.161 + fail("opening PTestOpensOpened"); 1.162 + return true; 1.163 +} 1.164 + 1.165 +static void 1.166 +OpenChild(TestOpensOpenedChild* aChild, 1.167 + Transport* aTransport, ProcessHandle aOtherProcess) 1.168 +{ 1.169 + AssertNotMainThread(); 1.170 + 1.171 + // Open the actor on the off-main thread to park it there. 1.172 + // Messages will be delivered to this thread's message loop 1.173 + // instead of the main thread's. 1.174 + if (!aChild->Open(aTransport, aOtherProcess, 1.175 + XRE_GetIOMessageLoop(), ipc::ChildSide)) 1.176 + fail("opening Child"); 1.177 + 1.178 + // Kick off the unit tests 1.179 + if (!aChild->SendHello()) 1.180 + fail("sending Hello"); 1.181 +} 1.182 + 1.183 +PTestOpensOpenedChild* 1.184 +TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport, 1.185 + ProcessId otherProcess) 1.186 +{ 1.187 + gMainThread = MessageLoop::current(); 1.188 + 1.189 + ProcessHandle h; 1.190 + if (!base::OpenProcessHandle(otherProcess, &h)) { 1.191 + return nullptr; 1.192 + } 1.193 + 1.194 + gChildThread = new Thread("ChildThread"); 1.195 + if (!gChildThread->Start()) 1.196 + fail("starting child thread"); 1.197 + 1.198 + TestOpensOpenedChild* a = new TestOpensOpenedChild(transport); 1.199 + gChildThread->message_loop()->PostTask( 1.200 + FROM_HERE, 1.201 + NewRunnableFunction(OpenChild, a, transport, h)); 1.202 + 1.203 + return a; 1.204 +} 1.205 + 1.206 +void 1.207 +TestOpensChild::ActorDestroy(ActorDestroyReason why) 1.208 +{ 1.209 + // Stops the thread and joins it 1.210 + delete gChildThread; 1.211 + 1.212 + if (NormalShutdown != why) 1.213 + fail("unexpected destruction!"); 1.214 + QuitChild(); 1.215 +} 1.216 + 1.217 +bool 1.218 +TestOpensOpenedChild::RecvHi() 1.219 +{ 1.220 + AssertNotMainThread(); 1.221 + 1.222 + if (!SendHelloSync()) 1.223 + fail("sending HelloSync"); 1.224 + if (!CallHelloRpc()) 1.225 + fail("calling HelloRpc"); 1.226 + if (!mGotHi) 1.227 + fail("didn't answer HiRpc"); 1.228 + 1.229 + // Need to close the channel without message-processing frames on 1.230 + // the C++ stack 1.231 + MessageLoop::current()->PostTask( 1.232 + FROM_HERE, 1.233 + NewRunnableMethod(this, &TestOpensOpenedChild::Close)); 1.234 + return true; 1.235 +} 1.236 + 1.237 +bool 1.238 +TestOpensOpenedChild::AnswerHiRpc() 1.239 +{ 1.240 + AssertNotMainThread(); 1.241 + 1.242 + mGotHi = true; // d00d 1.243 + return true; 1.244 +} 1.245 + 1.246 +static void 1.247 +ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child, 1.248 + Transport* transport) 1.249 +{ 1.250 + delete child; 1.251 + 1.252 + // Now delete the transport, which has to happen after the 1.253 + // top-level actor is deleted. 1.254 + XRE_GetIOMessageLoop()->PostTask( 1.255 + FROM_HERE, 1.256 + new DeleteTask<Transport>(transport)); 1.257 + 1.258 + // Kick off main-thread shutdown. 1.259 + gMainThread->PostTask( 1.260 + FROM_HERE, 1.261 + NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); 1.262 +} 1.263 + 1.264 +void 1.265 +TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) 1.266 +{ 1.267 + AssertNotMainThread(); 1.268 + 1.269 + if (NormalShutdown != why) 1.270 + fail("unexpected destruction!"); 1.271 + 1.272 + // ActorDestroy() is just a callback from IPDL-generated code, 1.273 + // which needs the top-level actor (this) to stay alive a little 1.274 + // longer so other things can be cleaned up. Defer shutdown to 1.275 + // let cleanup finish. 1.276 + MessageLoop::current()->PostTask( 1.277 + FROM_HERE, 1.278 + NewRunnableFunction(ShutdownTestOpensOpenedChild, 1.279 + this, mTransport)); 1.280 +} 1.281 + 1.282 +} // namespace mozilla