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