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