Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 #include "base/thread.h"
3 #include "TestOpens.h"
5 #include "IPDLUnitTests.h" // fail etc.
7 template<>
8 struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensChild>
9 {
10 static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
11 static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
12 };
14 template<>
15 struct RunnableMethodTraits<mozilla::_ipdltest2::TestOpensOpenedChild>
16 {
17 static void RetainCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { }
18 static void ReleaseCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { }
19 };
21 using namespace base;
22 using namespace mozilla::ipc;
24 namespace mozilla {
25 // NB: this is generally bad style, but I am lazy.
26 using namespace _ipdltest;
27 using namespace _ipdltest2;
29 static MessageLoop* gMainThread;
31 static void
32 AssertNotMainThread()
33 {
34 if (!gMainThread)
35 fail("gMainThread is not initialized");
36 if (MessageLoop::current() == gMainThread)
37 fail("unexpectedly called on the main thread");
38 }
40 //-----------------------------------------------------------------------------
41 // parent
43 // Thread on which TestOpensOpenedParent runs
44 static Thread* gParentThread;
46 void
47 TestOpensParent::Main()
48 {
49 if (!SendStart())
50 fail("sending Start");
51 }
53 static void
54 OpenParent(TestOpensOpenedParent* aParent,
55 Transport* aTransport, ProcessHandle aOtherProcess)
56 {
57 AssertNotMainThread();
59 // Open the actor on the off-main thread to park it there.
60 // Messages will be delivered to this thread's message loop
61 // instead of the main thread's.
62 if (!aParent->Open(aTransport, aOtherProcess,
63 XRE_GetIOMessageLoop(), ipc::ParentSide))
64 fail("opening Parent");
65 }
67 PTestOpensOpenedParent*
68 TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport,
69 ProcessId otherProcess)
70 {
71 gMainThread = MessageLoop::current();
73 ProcessHandle h;
74 if (!base::OpenProcessHandle(otherProcess, &h)) {
75 return nullptr;
76 }
78 gParentThread = new Thread("ParentThread");
79 if (!gParentThread->Start())
80 fail("starting parent thread");
82 TestOpensOpenedParent* a = new TestOpensOpenedParent(transport);
83 gParentThread->message_loop()->PostTask(
84 FROM_HERE,
85 NewRunnableFunction(OpenParent, a, transport, h));
87 return a;
88 }
90 void
91 TestOpensParent::ActorDestroy(ActorDestroyReason why)
92 {
93 // Stops the thread and joins it
94 delete gParentThread;
96 if (NormalShutdown != why)
97 fail("unexpected destruction!");
98 passed("ok");
99 QuitParent();
100 }
102 bool
103 TestOpensOpenedParent::RecvHello()
104 {
105 AssertNotMainThread();
106 return SendHi();
107 }
109 bool
110 TestOpensOpenedParent::RecvHelloSync()
111 {
112 AssertNotMainThread();
113 return true;
114 }
116 bool
117 TestOpensOpenedParent::AnswerHelloRpc()
118 {
119 AssertNotMainThread();
120 return CallHiRpc();
121 }
123 void
124 TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
125 {
126 AssertNotMainThread();
128 if (NormalShutdown != why)
129 fail("unexpected destruction!");
131 // ActorDestroy() is just a callback from IPDL-generated code,
132 // which needs the top-level actor (this) to stay alive a little
133 // longer so other things can be cleaned up.
134 MessageLoop::current()->PostTask(
135 FROM_HERE,
136 new DeleteTask<TestOpensOpenedParent>(this));
137 XRE_GetIOMessageLoop()->PostTask(
138 FROM_HERE,
139 new DeleteTask<Transport>(mTransport));
140 }
142 //-----------------------------------------------------------------------------
143 // child
145 static TestOpensChild* gOpensChild;
146 // Thread on which TestOpensOpenedChild runs
147 static Thread* gChildThread;
149 TestOpensChild::TestOpensChild()
150 {
151 gOpensChild = this;
152 }
154 bool
155 TestOpensChild::RecvStart()
156 {
157 if (!PTestOpensOpened::Open(this))
158 fail("opening PTestOpensOpened");
159 return true;
160 }
162 static void
163 OpenChild(TestOpensOpenedChild* aChild,
164 Transport* aTransport, ProcessHandle aOtherProcess)
165 {
166 AssertNotMainThread();
168 // Open the actor on the off-main thread to park it there.
169 // Messages will be delivered to this thread's message loop
170 // instead of the main thread's.
171 if (!aChild->Open(aTransport, aOtherProcess,
172 XRE_GetIOMessageLoop(), ipc::ChildSide))
173 fail("opening Child");
175 // Kick off the unit tests
176 if (!aChild->SendHello())
177 fail("sending Hello");
178 }
180 PTestOpensOpenedChild*
181 TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport,
182 ProcessId otherProcess)
183 {
184 gMainThread = MessageLoop::current();
186 ProcessHandle h;
187 if (!base::OpenProcessHandle(otherProcess, &h)) {
188 return nullptr;
189 }
191 gChildThread = new Thread("ChildThread");
192 if (!gChildThread->Start())
193 fail("starting child thread");
195 TestOpensOpenedChild* a = new TestOpensOpenedChild(transport);
196 gChildThread->message_loop()->PostTask(
197 FROM_HERE,
198 NewRunnableFunction(OpenChild, a, transport, h));
200 return a;
201 }
203 void
204 TestOpensChild::ActorDestroy(ActorDestroyReason why)
205 {
206 // Stops the thread and joins it
207 delete gChildThread;
209 if (NormalShutdown != why)
210 fail("unexpected destruction!");
211 QuitChild();
212 }
214 bool
215 TestOpensOpenedChild::RecvHi()
216 {
217 AssertNotMainThread();
219 if (!SendHelloSync())
220 fail("sending HelloSync");
221 if (!CallHelloRpc())
222 fail("calling HelloRpc");
223 if (!mGotHi)
224 fail("didn't answer HiRpc");
226 // Need to close the channel without message-processing frames on
227 // the C++ stack
228 MessageLoop::current()->PostTask(
229 FROM_HERE,
230 NewRunnableMethod(this, &TestOpensOpenedChild::Close));
231 return true;
232 }
234 bool
235 TestOpensOpenedChild::AnswerHiRpc()
236 {
237 AssertNotMainThread();
239 mGotHi = true; // d00d
240 return true;
241 }
243 static void
244 ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child,
245 Transport* transport)
246 {
247 delete child;
249 // Now delete the transport, which has to happen after the
250 // top-level actor is deleted.
251 XRE_GetIOMessageLoop()->PostTask(
252 FROM_HERE,
253 new DeleteTask<Transport>(transport));
255 // Kick off main-thread shutdown.
256 gMainThread->PostTask(
257 FROM_HERE,
258 NewRunnableMethod(gOpensChild, &TestOpensChild::Close));
259 }
261 void
262 TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
263 {
264 AssertNotMainThread();
266 if (NormalShutdown != why)
267 fail("unexpected destruction!");
269 // ActorDestroy() is just a callback from IPDL-generated code,
270 // which needs the top-level actor (this) to stay alive a little
271 // longer so other things can be cleaned up. Defer shutdown to
272 // let cleanup finish.
273 MessageLoop::current()->PostTask(
274 FROM_HERE,
275 NewRunnableFunction(ShutdownTestOpensOpenedChild,
276 this, mTransport));
277 }
279 } // namespace mozilla