ipc/ipdl/test/cxx/TestOpens.cpp

branch
TOR_BUG_3246
changeset 6
8bccb770b82d
equal deleted inserted replaced
-1:000000000000 0:41ce19c3f45e
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

mercurial