|
1 #include "base/thread.h" |
|
2 |
|
3 #include "TestOpens.h" |
|
4 |
|
5 #include "IPDLUnitTests.h" // fail etc. |
|
6 |
|
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 }; |
|
13 |
|
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 }; |
|
20 |
|
21 using namespace base; |
|
22 using namespace mozilla::ipc; |
|
23 |
|
24 namespace mozilla { |
|
25 // NB: this is generally bad style, but I am lazy. |
|
26 using namespace _ipdltest; |
|
27 using namespace _ipdltest2; |
|
28 |
|
29 static MessageLoop* gMainThread; |
|
30 |
|
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 } |
|
39 |
|
40 //----------------------------------------------------------------------------- |
|
41 // parent |
|
42 |
|
43 // Thread on which TestOpensOpenedParent runs |
|
44 static Thread* gParentThread; |
|
45 |
|
46 void |
|
47 TestOpensParent::Main() |
|
48 { |
|
49 if (!SendStart()) |
|
50 fail("sending Start"); |
|
51 } |
|
52 |
|
53 static void |
|
54 OpenParent(TestOpensOpenedParent* aParent, |
|
55 Transport* aTransport, ProcessHandle aOtherProcess) |
|
56 { |
|
57 AssertNotMainThread(); |
|
58 |
|
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 } |
|
66 |
|
67 PTestOpensOpenedParent* |
|
68 TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport, |
|
69 ProcessId otherProcess) |
|
70 { |
|
71 gMainThread = MessageLoop::current(); |
|
72 |
|
73 ProcessHandle h; |
|
74 if (!base::OpenProcessHandle(otherProcess, &h)) { |
|
75 return nullptr; |
|
76 } |
|
77 |
|
78 gParentThread = new Thread("ParentThread"); |
|
79 if (!gParentThread->Start()) |
|
80 fail("starting parent thread"); |
|
81 |
|
82 TestOpensOpenedParent* a = new TestOpensOpenedParent(transport); |
|
83 gParentThread->message_loop()->PostTask( |
|
84 FROM_HERE, |
|
85 NewRunnableFunction(OpenParent, a, transport, h)); |
|
86 |
|
87 return a; |
|
88 } |
|
89 |
|
90 void |
|
91 TestOpensParent::ActorDestroy(ActorDestroyReason why) |
|
92 { |
|
93 // Stops the thread and joins it |
|
94 delete gParentThread; |
|
95 |
|
96 if (NormalShutdown != why) |
|
97 fail("unexpected destruction!"); |
|
98 passed("ok"); |
|
99 QuitParent(); |
|
100 } |
|
101 |
|
102 bool |
|
103 TestOpensOpenedParent::RecvHello() |
|
104 { |
|
105 AssertNotMainThread(); |
|
106 return SendHi(); |
|
107 } |
|
108 |
|
109 bool |
|
110 TestOpensOpenedParent::RecvHelloSync() |
|
111 { |
|
112 AssertNotMainThread(); |
|
113 return true; |
|
114 } |
|
115 |
|
116 bool |
|
117 TestOpensOpenedParent::AnswerHelloRpc() |
|
118 { |
|
119 AssertNotMainThread(); |
|
120 return CallHiRpc(); |
|
121 } |
|
122 |
|
123 void |
|
124 TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why) |
|
125 { |
|
126 AssertNotMainThread(); |
|
127 |
|
128 if (NormalShutdown != why) |
|
129 fail("unexpected destruction!"); |
|
130 |
|
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 } |
|
141 |
|
142 //----------------------------------------------------------------------------- |
|
143 // child |
|
144 |
|
145 static TestOpensChild* gOpensChild; |
|
146 // Thread on which TestOpensOpenedChild runs |
|
147 static Thread* gChildThread; |
|
148 |
|
149 TestOpensChild::TestOpensChild() |
|
150 { |
|
151 gOpensChild = this; |
|
152 } |
|
153 |
|
154 bool |
|
155 TestOpensChild::RecvStart() |
|
156 { |
|
157 if (!PTestOpensOpened::Open(this)) |
|
158 fail("opening PTestOpensOpened"); |
|
159 return true; |
|
160 } |
|
161 |
|
162 static void |
|
163 OpenChild(TestOpensOpenedChild* aChild, |
|
164 Transport* aTransport, ProcessHandle aOtherProcess) |
|
165 { |
|
166 AssertNotMainThread(); |
|
167 |
|
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"); |
|
174 |
|
175 // Kick off the unit tests |
|
176 if (!aChild->SendHello()) |
|
177 fail("sending Hello"); |
|
178 } |
|
179 |
|
180 PTestOpensOpenedChild* |
|
181 TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport, |
|
182 ProcessId otherProcess) |
|
183 { |
|
184 gMainThread = MessageLoop::current(); |
|
185 |
|
186 ProcessHandle h; |
|
187 if (!base::OpenProcessHandle(otherProcess, &h)) { |
|
188 return nullptr; |
|
189 } |
|
190 |
|
191 gChildThread = new Thread("ChildThread"); |
|
192 if (!gChildThread->Start()) |
|
193 fail("starting child thread"); |
|
194 |
|
195 TestOpensOpenedChild* a = new TestOpensOpenedChild(transport); |
|
196 gChildThread->message_loop()->PostTask( |
|
197 FROM_HERE, |
|
198 NewRunnableFunction(OpenChild, a, transport, h)); |
|
199 |
|
200 return a; |
|
201 } |
|
202 |
|
203 void |
|
204 TestOpensChild::ActorDestroy(ActorDestroyReason why) |
|
205 { |
|
206 // Stops the thread and joins it |
|
207 delete gChildThread; |
|
208 |
|
209 if (NormalShutdown != why) |
|
210 fail("unexpected destruction!"); |
|
211 QuitChild(); |
|
212 } |
|
213 |
|
214 bool |
|
215 TestOpensOpenedChild::RecvHi() |
|
216 { |
|
217 AssertNotMainThread(); |
|
218 |
|
219 if (!SendHelloSync()) |
|
220 fail("sending HelloSync"); |
|
221 if (!CallHelloRpc()) |
|
222 fail("calling HelloRpc"); |
|
223 if (!mGotHi) |
|
224 fail("didn't answer HiRpc"); |
|
225 |
|
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 } |
|
233 |
|
234 bool |
|
235 TestOpensOpenedChild::AnswerHiRpc() |
|
236 { |
|
237 AssertNotMainThread(); |
|
238 |
|
239 mGotHi = true; // d00d |
|
240 return true; |
|
241 } |
|
242 |
|
243 static void |
|
244 ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child, |
|
245 Transport* transport) |
|
246 { |
|
247 delete child; |
|
248 |
|
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)); |
|
254 |
|
255 // Kick off main-thread shutdown. |
|
256 gMainThread->PostTask( |
|
257 FROM_HERE, |
|
258 NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); |
|
259 } |
|
260 |
|
261 void |
|
262 TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) |
|
263 { |
|
264 AssertNotMainThread(); |
|
265 |
|
266 if (NormalShutdown != why) |
|
267 fail("unexpected destruction!"); |
|
268 |
|
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 } |
|
278 |
|
279 } // namespace mozilla |