1 //
2 // Autogenerated from Python template. Hands off.
3 //
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "IPDLUnitTests.h"
9
10 #include "base/command_line.h"
11 #include "base/string_util.h"
12 #include "base/task.h"
13 #include "base/thread.h"
14
15 #include "nsRegion.h"
16
17 #include "IPDLUnitTestSubprocess.h"
18
19 //-----------------------------------------------------------------------------
20 //===== TEMPLATED =====
21 ${INCLUDES}
22 //-----------------------------------------------------------------------------
23
24 using namespace std;
25
26 using base::Thread;
27
28 namespace mozilla {
29 namespace _ipdltest {
30
31 void* gParentActor;
32 IPDLUnitTestSubprocess* gSubprocess;
33
34 void* gChildActor;
35
36 // Note: in threaded mode, this will be non-null (for both parent and
37 // child, since they share one set of globals).
38 Thread* gChildThread;
39 MessageLoop *gParentMessageLoop;
40 bool gParentDone;
41 bool gChildDone;
42
43 void
44 DeleteChildActor();
45
46 //-----------------------------------------------------------------------------
47 // data/functions accessed by both parent and child processes
48
49 char* gIPDLUnitTestName = nullptr;
50
51 const char*
IPDLUnitTestName()52 IPDLUnitTestName()
53 {
54 if (!gIPDLUnitTestName) {
55 #if defined(OS_WIN)
56 vector<wstring> args =
57 CommandLine::ForCurrentProcess()->GetLooseValues();
58 gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str());
59 #elif defined(OS_POSIX)
60 vector<string> argv = CommandLine::ForCurrentProcess()->argv();
61 gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str());
62 #else
63 # error Sorry
64 #endif
65 }
66 return gIPDLUnitTestName;
67 }
68
69 } // namespace _ipdltest
70 } // namespace mozilla
71
72
73 namespace {
74
75 enum IPDLUnitTestType {
76 NoneTest = 0,
77
78 //-----------------------------------------------------------------------------
79 //===== TEMPLATED =====
80 ${ENUM_VALUES}
81
82 LastTest = ${LAST_ENUM}
83 //-----------------------------------------------------------------------------
84 };
85
86
87 IPDLUnitTestType
IPDLUnitTestFromString(const char * const aString)88 IPDLUnitTestFromString(const char* const aString)
89 {
90 if (!aString)
91 return static_cast<IPDLUnitTestType>(0);
92 //-----------------------------------------------------------------------------
93 //===== TEMPLATED =====
94 ${STRING_TO_ENUMS}
95 //-----------------------------------------------------------------------------
96 else
97 return static_cast<IPDLUnitTestType>(0);
98 }
99
100
101 const char*
IPDLUnitTestToString(IPDLUnitTestType aTest)102 IPDLUnitTestToString(IPDLUnitTestType aTest)
103 {
104 switch (aTest) {
105 //-----------------------------------------------------------------------------
106 //===== TEMPLATED =====
107 ${ENUM_TO_STRINGS}
108 //-----------------------------------------------------------------------------
109
110 default:
111 return nullptr;
112 }
113 }
114
115
116 IPDLUnitTestType
IPDLUnitTest()117 IPDLUnitTest()
118 {
119 return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName());
120 }
121
122
123 } // namespace <anon>
124
125
126 //-----------------------------------------------------------------------------
127 // parent process only
128
129 namespace mozilla {
130 namespace _ipdltest {
131
132 void
133 DeferredParentShutdown();
134
135 void
136 IPDLUnitTestThreadMain(char *testString);
137
138 void
IPDLUnitTestMain(void * aData)139 IPDLUnitTestMain(void* aData)
140 {
141 char* testString = reinterpret_cast<char*>(aData);
142
143 // Check if we are to run the test using threads instead:
144 const char *prefix = "thread:";
145 const int prefixLen = strlen(prefix);
146 if (!strncmp(testString, prefix, prefixLen)) {
147 IPDLUnitTestThreadMain(testString + prefixLen);
148 return;
149 }
150
151 IPDLUnitTestType test = IPDLUnitTestFromString(testString);
152 if (!test) {
153 // use this instead of |fail()| because we don't know what the test is
154 fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
155 "<--->", testString);
156 NS_RUNTIMEABORT("can't continue");
157 }
158 gIPDLUnitTestName = testString;
159
160 // Check whether this test is enabled for processes:
161 switch (test) {
162 //-----------------------------------------------------------------------------
163 //===== TEMPLATED =====
164 ${PARENT_ENABLED_CASES_PROC}
165 //-----------------------------------------------------------------------------
166
167 default:
168 fail("not reached");
169 return; // unreached
170 }
171
172 printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
173
174 std::vector<std::string> testCaseArgs;
175 testCaseArgs.push_back(testString);
176
177 gSubprocess = new IPDLUnitTestSubprocess();
178 if (!gSubprocess->SyncLaunch(testCaseArgs))
179 fail("problem launching subprocess");
180
181 IPC::Channel* transport = gSubprocess->GetChannel();
182 if (!transport)
183 fail("no transport");
184
185 base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle());
186
187 switch (test) {
188 //-----------------------------------------------------------------------------
189 //===== TEMPLATED =====
190 ${PARENT_MAIN_CASES_PROC}
191 //-----------------------------------------------------------------------------
192
193 default:
194 fail("not reached");
195 return; // unreached
196 }
197 }
198
199 void
IPDLUnitTestThreadMain(char * testString)200 IPDLUnitTestThreadMain(char *testString)
201 {
202 IPDLUnitTestType test = IPDLUnitTestFromString(testString);
203 if (!test) {
204 // use this instead of |fail()| because we don't know what the test is
205 fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
206 "<--->", testString);
207 NS_RUNTIMEABORT("can't continue");
208 }
209 gIPDLUnitTestName = testString;
210
211 // Check whether this test is enabled for threads:
212 switch (test) {
213 //-----------------------------------------------------------------------------
214 //===== TEMPLATED =====
215 ${PARENT_ENABLED_CASES_THREAD}
216 //-----------------------------------------------------------------------------
217
218 default:
219 fail("not reached");
220 return; // unreached
221 }
222
223 printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
224
225 std::vector<std::string> testCaseArgs;
226 testCaseArgs.push_back(testString);
227
228 gChildThread = new Thread("ParentThread");
229 if (!gChildThread->Start())
230 fail("starting parent thread");
231
232 gParentMessageLoop = MessageLoop::current();
233 MessageLoop *childMessageLoop = gChildThread->message_loop();
234
235 switch (test) {
236 //-----------------------------------------------------------------------------
237 //===== TEMPLATED =====
238 ${PARENT_MAIN_CASES_THREAD}
239 //-----------------------------------------------------------------------------
240
241 default:
242 fail("not reached");
243 return; // unreached
244 }
245 }
246
247 void
DeleteParentActor()248 DeleteParentActor()
249 {
250 if (!gParentActor)
251 return;
252
253 switch (IPDLUnitTest()) {
254 //-----------------------------------------------------------------------------
255 //===== TEMPLATED =====
256 ${PARENT_DELETE_CASES}
257 //-----------------------------------------------------------------------------
258 default: ::mozilla::_ipdltest::fail("???");
259 }
260 }
261
262 void
QuitXPCOM()263 QuitXPCOM()
264 {
265 DeleteParentActor();
266
267 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
268 nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
269 appShell->Exit();
270 }
271
272 void
DeleteSubprocess(MessageLoop * uiLoop)273 DeleteSubprocess(MessageLoop* uiLoop)
274 {
275 // pong to QuitXPCOM
276 delete gSubprocess;
277 uiLoop->PostTask(NewRunnableFunction(QuitXPCOM));
278 }
279
280 void
DeferredParentShutdown()281 DeferredParentShutdown()
282 {
283 // ping to DeleteSubprocess
284 XRE_GetIOMessageLoop()->PostTask(
285 NewRunnableFunction(DeleteSubprocess, MessageLoop::current()));
286 }
287
288 void
TryThreadedShutdown()289 TryThreadedShutdown()
290 {
291 // Stop if either:
292 // - the child has not finished,
293 // - the parent has not finished,
294 // - or this code has already executed.
295 // Remember: this TryThreadedShutdown() task is enqueued
296 // by both parent and child (though always on parent's msg loop).
297 if (!gChildDone || !gParentDone || !gChildThread)
298 return;
299
300 delete gChildThread;
301 gChildThread = 0;
302 DeferredParentShutdown();
303 }
304
305 void
ChildCompleted()306 ChildCompleted()
307 {
308 // Executes on the parent message loop once child has completed.
309 gChildDone = true;
310 TryThreadedShutdown();
311 }
312
313 void
QuitParent()314 QuitParent()
315 {
316 if (gChildThread) {
317 gParentDone = true;
318 MessageLoop::current()->PostTask(
319 NewRunnableFunction(TryThreadedShutdown));
320 } else {
321 // defer "real" shutdown to avoid *Channel::Close() racing with the
322 // deletion of the subprocess
323 MessageLoop::current()->PostTask(
324 NewRunnableFunction(DeferredParentShutdown));
325 }
326 }
327
328 static void
ChildDie()329 ChildDie()
330 {
331 DeleteChildActor();
332 XRE_ShutdownChildProcess();
333 }
334
335 void
QuitChild()336 QuitChild()
337 {
338 if (gChildThread) { // Threaded-mode test
339 gParentMessageLoop->PostTask(
340 NewRunnableFunction(ChildCompleted));
341 } else { // Process-mode test
342 MessageLoop::current()->PostTask(
343 NewRunnableFunction(ChildDie));
344 }
345 }
346
347 } // namespace _ipdltest
348 } // namespace mozilla
349
350
351 //-----------------------------------------------------------------------------
352 // child process only
353
354 namespace mozilla {
355 namespace _ipdltest {
356
357 void
DeleteChildActor()358 DeleteChildActor()
359 {
360 if (!gChildActor)
361 return;
362
363 switch (IPDLUnitTest()) {
364 //-----------------------------------------------------------------------------
365 //===== TEMPLATED =====
366 ${CHILD_DELETE_CASES}
367 //-----------------------------------------------------------------------------
368 default: ::mozilla::_ipdltest::fail("???");
369 }
370 }
371
372 void
IPDLUnitTestChildInit(IPC::Channel * transport,base::ProcessId parentPid,MessageLoop * worker)373 IPDLUnitTestChildInit(IPC::Channel* transport,
374 base::ProcessId parentPid,
375 MessageLoop* worker)
376 {
377 switch (IPDLUnitTest()) {
378 //-----------------------------------------------------------------------------
379 //===== TEMPLATED =====
380 ${CHILD_INIT_CASES}
381 //-----------------------------------------------------------------------------
382
383 default:
384 fail("not reached");
385 return; // unreached
386 }
387 }
388
389 } // namespace _ipdltest
390 } // namespace mozilla
391