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