michael@0: // michael@0: // Autogenerated from Python template. Hands off. michael@0: // michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "IPDLUnitTests.h" michael@0: michael@0: #include "base/command_line.h" michael@0: #include "base/string_util.h" michael@0: #include "base/thread.h" michael@0: michael@0: #include "nsRegion.h" michael@0: michael@0: #include "IPDLUnitTestSubprocess.h" michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${INCLUDES} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: using namespace base; michael@0: using namespace std; michael@0: michael@0: namespace mozilla { michael@0: namespace _ipdltest { michael@0: michael@0: void* gParentActor; michael@0: IPDLUnitTestSubprocess* gSubprocess; michael@0: michael@0: void* gChildActor; michael@0: michael@0: // Note: in threaded mode, this will be non-null (for both parent and michael@0: // child, since they share one set of globals). michael@0: Thread* gChildThread; michael@0: MessageLoop *gParentMessageLoop; michael@0: bool gParentDone; michael@0: bool gChildDone; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // data/functions accessed by both parent and child processes michael@0: michael@0: char* gIPDLUnitTestName = nullptr; michael@0: michael@0: const char* const michael@0: IPDLUnitTestName() michael@0: { michael@0: if (!gIPDLUnitTestName) { michael@0: #if defined(OS_WIN) michael@0: vector args = michael@0: CommandLine::ForCurrentProcess()->GetLooseValues(); michael@0: gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str()); michael@0: #elif defined(OS_POSIX) michael@0: vector argv = CommandLine::ForCurrentProcess()->argv(); michael@0: gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str()); michael@0: #else michael@0: # error Sorry michael@0: #endif michael@0: } michael@0: return gIPDLUnitTestName; michael@0: } michael@0: michael@0: } // namespace _ipdltest michael@0: } // namespace mozilla michael@0: michael@0: michael@0: namespace { michael@0: michael@0: enum IPDLUnitTestType { michael@0: NoneTest = 0, michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${ENUM_VALUES} michael@0: michael@0: LastTest = ${LAST_ENUM} michael@0: //----------------------------------------------------------------------------- michael@0: }; michael@0: michael@0: michael@0: IPDLUnitTestType michael@0: IPDLUnitTestFromString(const char* const aString) michael@0: { michael@0: if (!aString) michael@0: return static_cast(0); michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${STRING_TO_ENUMS} michael@0: //----------------------------------------------------------------------------- michael@0: else michael@0: return static_cast(0); michael@0: } michael@0: michael@0: michael@0: const char* const michael@0: IPDLUnitTestToString(IPDLUnitTestType aTest) michael@0: { michael@0: switch (aTest) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${ENUM_TO_STRINGS} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: michael@0: IPDLUnitTestType michael@0: IPDLUnitTest() michael@0: { michael@0: return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName()); michael@0: } michael@0: michael@0: michael@0: } // namespace michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // parent process only michael@0: michael@0: namespace mozilla { michael@0: namespace _ipdltest { michael@0: michael@0: void michael@0: DeferredParentShutdown(); michael@0: michael@0: void michael@0: IPDLUnitTestThreadMain(char *testString); michael@0: michael@0: void michael@0: IPDLUnitTestMain(void* aData) michael@0: { michael@0: char* testString = reinterpret_cast(aData); michael@0: michael@0: // Check if we are to run the test using threads instead: michael@0: const char *prefix = "thread:"; michael@0: const int prefixLen = strlen(prefix); michael@0: if (!strncmp(testString, prefix, prefixLen)) { michael@0: IPDLUnitTestThreadMain(testString + prefixLen); michael@0: return; michael@0: } michael@0: michael@0: IPDLUnitTestType test = IPDLUnitTestFromString(testString); michael@0: if (!test) { michael@0: // use this instead of |fail()| because we don't know what the test is michael@0: fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", michael@0: "<--->", testString); michael@0: NS_RUNTIMEABORT("can't continue"); michael@0: } michael@0: gIPDLUnitTestName = testString; michael@0: michael@0: // Check whether this test is enabled for processes: michael@0: switch (test) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${PARENT_ENABLED_CASES_PROC} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: fail("not reached"); michael@0: return; // unreached michael@0: } michael@0: michael@0: printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); michael@0: michael@0: std::vector testCaseArgs; michael@0: testCaseArgs.push_back(testString); michael@0: michael@0: gSubprocess = new IPDLUnitTestSubprocess(); michael@0: if (!gSubprocess->SyncLaunch(testCaseArgs)) michael@0: fail("problem launching subprocess"); michael@0: michael@0: IPC::Channel* transport = gSubprocess->GetChannel(); michael@0: if (!transport) michael@0: fail("no transport"); michael@0: michael@0: base::ProcessHandle child = gSubprocess->GetChildProcessHandle(); michael@0: michael@0: switch (test) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${PARENT_MAIN_CASES_PROC} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: fail("not reached"); michael@0: return; // unreached michael@0: } michael@0: } michael@0: michael@0: void michael@0: IPDLUnitTestThreadMain(char *testString) michael@0: { michael@0: IPDLUnitTestType test = IPDLUnitTestFromString(testString); michael@0: if (!test) { michael@0: // use this instead of |fail()| because we don't know what the test is michael@0: fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n", michael@0: "<--->", testString); michael@0: NS_RUNTIMEABORT("can't continue"); michael@0: } michael@0: gIPDLUnitTestName = testString; michael@0: michael@0: // Check whether this test is enabled for threads: michael@0: switch (test) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${PARENT_ENABLED_CASES_THREAD} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: fail("not reached"); michael@0: return; // unreached michael@0: } michael@0: michael@0: printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName); michael@0: michael@0: std::vector testCaseArgs; michael@0: testCaseArgs.push_back(testString); michael@0: michael@0: gChildThread = new Thread("ParentThread"); michael@0: if (!gChildThread->Start()) michael@0: fail("starting parent thread"); michael@0: michael@0: gParentMessageLoop = MessageLoop::current(); michael@0: MessageLoop *childMessageLoop = gChildThread->message_loop(); michael@0: michael@0: switch (test) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${PARENT_MAIN_CASES_THREAD} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: fail("not reached"); michael@0: return; // unreached michael@0: } michael@0: } michael@0: michael@0: void michael@0: DeleteParentActor() michael@0: { michael@0: if (!gParentActor) michael@0: return; michael@0: michael@0: switch (IPDLUnitTest()) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${PARENT_DELETE_CASES} michael@0: //----------------------------------------------------------------------------- michael@0: default: ::mozilla::_ipdltest::fail("???"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: QuitXPCOM() michael@0: { michael@0: DeleteParentActor(); michael@0: michael@0: static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); michael@0: nsCOMPtr appShell (do_GetService(kAppShellCID)); michael@0: appShell->Exit(); michael@0: } michael@0: michael@0: void michael@0: DeleteSubprocess(MessageLoop* uiLoop) michael@0: { michael@0: // pong to QuitXPCOM michael@0: delete gSubprocess; michael@0: uiLoop->PostTask(FROM_HERE, NewRunnableFunction(QuitXPCOM)); michael@0: } michael@0: michael@0: void michael@0: DeferredParentShutdown() michael@0: { michael@0: // ping to DeleteSubprocess michael@0: XRE_GetIOMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(DeleteSubprocess, MessageLoop::current())); michael@0: } michael@0: michael@0: void michael@0: TryThreadedShutdown() michael@0: { michael@0: // Stop if either: michael@0: // - the child has not finished, michael@0: // - the parent has not finished, michael@0: // - or this code has already executed. michael@0: // Remember: this TryThreadedShutdown() task is enqueued michael@0: // by both parent and child (though always on parent's msg loop). michael@0: if (!gChildDone || !gParentDone || !gChildThread) michael@0: return; michael@0: michael@0: delete gChildThread; michael@0: gChildThread = 0; michael@0: DeferredParentShutdown(); michael@0: } michael@0: michael@0: void michael@0: ChildCompleted() michael@0: { michael@0: // Executes on the parent message loop once child has completed. michael@0: gChildDone = true; michael@0: TryThreadedShutdown(); michael@0: } michael@0: michael@0: void michael@0: QuitParent() michael@0: { michael@0: if (gChildThread) { michael@0: gParentDone = true; michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, NewRunnableFunction(TryThreadedShutdown)); michael@0: } else { michael@0: // defer "real" shutdown to avoid *Channel::Close() racing with the michael@0: // deletion of the subprocess michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, NewRunnableFunction(DeferredParentShutdown)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: QuitChild() michael@0: { michael@0: if (gChildThread) { // Threaded-mode test michael@0: gParentMessageLoop->PostTask( michael@0: FROM_HERE, NewRunnableFunction(ChildCompleted)); michael@0: } else { // Process-mode test michael@0: XRE_ShutdownChildProcess(); michael@0: } michael@0: } michael@0: michael@0: } // namespace _ipdltest michael@0: } // namespace mozilla michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // child process only michael@0: michael@0: namespace mozilla { michael@0: namespace _ipdltest { michael@0: michael@0: void michael@0: DeleteChildActor() michael@0: { michael@0: if (!gChildActor) michael@0: return; michael@0: michael@0: switch (IPDLUnitTest()) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${CHILD_DELETE_CASES} michael@0: //----------------------------------------------------------------------------- michael@0: default: ::mozilla::_ipdltest::fail("???"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: IPDLUnitTestChildInit(IPC::Channel* transport, michael@0: base::ProcessHandle parent, michael@0: MessageLoop* worker) michael@0: { michael@0: if (atexit(DeleteChildActor)) michael@0: fail("can't install atexit() handler"); michael@0: michael@0: switch (IPDLUnitTest()) { michael@0: //----------------------------------------------------------------------------- michael@0: //===== TEMPLATED ===== michael@0: ${CHILD_INIT_CASES} michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: default: michael@0: fail("not reached"); michael@0: return; // unreached michael@0: } michael@0: } michael@0: michael@0: } // namespace _ipdltest michael@0: } // namespace mozilla