diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /ipc/ipdl/test/cxx | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/ipdl/test/cxx')
154 files changed, 11206 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp new file mode 100644 index 0000000000..7683808535 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp @@ -0,0 +1,27 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ipc/IOThreadChild.h" + +#include "IPDLUnitTestProcessChild.h" +#include "IPDLUnitTests.h" + +#include "nsRegion.h" + +using mozilla::ipc::IOThreadChild; + +namespace mozilla { +namespace _ipdltest { + +bool IPDLUnitTestProcessChild::Init(int aArgc, char* aArgv[]) { + // FIXME(nika): this is quite clearly broken and needs to be fixed. + IPDLUnitTestChildInit(IOThreadChild::TakeChannel(), ParentPid(), + IOThreadChild::message_loop()); + + return true; +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h new file mode 100644 index 0000000000..94578e3520 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h @@ -0,0 +1,28 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h +#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1 + +#include "mozilla/ipc/ProcessChild.h" + +namespace mozilla { +namespace _ipdltest { + +class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild { + typedef mozilla::ipc::ProcessChild ProcessChild; + + public: + using ProcessChild::ProcessChild; + + ~IPDLUnitTestProcessChild() {} + + virtual bool Init(int aArgc, char* aArgv[]) override; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp new file mode 100644 index 0000000000..660e5928d3 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp @@ -0,0 +1,19 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "IPDLUnitTestSubprocess.h" + +using mozilla::ipc::GeckoChildProcessHost; + +namespace mozilla { +namespace _ipdltest { + +IPDLUnitTestSubprocess::IPDLUnitTestSubprocess() + : GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest) {} + +IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess() {} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h new file mode 100644 index 0000000000..384cf25ce9 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h +#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1 + +#include "mozilla/ipc/GeckoChildProcessHost.h" + +namespace mozilla { +namespace _ipdltest { +//----------------------------------------------------------------------------- + +class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost { + public: + IPDLUnitTestSubprocess(); + + /** + * Asynchronously launch the plugin process. + */ + // Could override parent Launch, but don't need to here + // bool Launch(); + + private: + ~IPDLUnitTestSubprocess(); + + DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess); +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h b/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h new file mode 100644 index 0000000000..02696f7df7 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla__ipdltest_IPDLUnitTestTypes_h +#define mozilla__ipdltest_IPDLUnitTestTypes_h + +#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason + +namespace mozilla { +namespace _ipdltest { + +struct DirtyRect { + int x; + int y; + int w; + int h; +}; + +} // namespace _ipdltest +} // namespace mozilla + +namespace IPC { +template <> +struct ParamTraits<mozilla::_ipdltest::DirtyRect> { + typedef mozilla::_ipdltest::DirtyRect paramType; + static void Write(MessageWriter* aWriter, const paramType& aParam) { + WriteParam(aWriter, aParam.x); + WriteParam(aWriter, aParam.y); + WriteParam(aWriter, aParam.w); + WriteParam(aWriter, aParam.h); + } + static bool Read(MessageReader* aReader, void** aIter, paramType* aResult) { + return (ReadParam(aReader, aIter, &aResult->x) && + ReadParam(aReader, aIter, &aResult->y) && + ReadParam(aReader, aIter, &aResult->w) && + ReadParam(aReader, aIter, &aResult->h)); + } +}; +} // namespace IPC + +#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h new file mode 100644 index 0000000000..e454ae7b61 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h @@ -0,0 +1,28 @@ + +#ifndef mozilla__ipdltest_IPDLUnitTestUtils +#define mozilla__ipdltest_IPDLUnitTestUtils 1 + +#include "ipc/IPCMessageUtils.h" + +namespace mozilla { +namespace _ipdltest { + +struct Bad {}; + +} // namespace _ipdltest +} // namespace mozilla + +namespace IPC { + +template <> +struct ParamTraits<mozilla::_ipdltest::Bad> { + typedef mozilla::_ipdltest::Bad paramType; + + // Defined in TestActorPunning.cpp. + static void Write(MessageWriter* aWriter, const paramType& aParam); + static bool Read(MessageReader* aReader, paramType* aResult); +}; + +} // namespace IPC + +#endif // mozilla__ipdltest_IPDLUnitTestUtils diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.h b/ipc/ipdl/test/cxx/IPDLUnitTests.h new file mode 100644 index 0000000000..28fc4ee372 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.h @@ -0,0 +1,85 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla__ipdltest_IPDLUnitTests_h +#define mozilla__ipdltest_IPDLUnitTests_h 1 + +#include "base/message_loop.h" +#include "base/process.h" +#include "chrome/common/ipc_channel.h" + +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsServiceManagerUtils.h" // do_GetService() +#include "nsWidgetsCID.h" // NS_APPSHELL_CID +#include "nsXULAppAPI.h" + +#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL" +#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS" +#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// both processes +const char* IPDLUnitTestName(); + +// NB: these are named like the similar functions in +// xpcom/test/TestHarness.h. The names should nominally be kept in +// sync. + +inline void fail(const char* fmt, ...) { + va_list ap; + + fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName()); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); + + MOZ_CRASH("failed test"); +} + +inline void passed(const char* fmt, ...) { + va_list ap; + + printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName()); + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + fputc('\n', stdout); +} + +//----------------------------------------------------------------------------- +// parent process only + +class IPDLUnitTestSubprocess; + +extern void* gParentActor; +extern IPDLUnitTestSubprocess* gSubprocess; + +void IPDLUnitTestMain(void* aData); + +void QuitParent(); + +//----------------------------------------------------------------------------- +// child process only + +extern void* gChildActor; + +void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid, + MessageLoop* worker); + +void QuitChild(); + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp new file mode 100644 index 0000000000..30eea42838 --- /dev/null +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp @@ -0,0 +1,347 @@ +// +// 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" + +// clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${INCLUDES} +//----------------------------------------------------------------------------- +// clang-format on + +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, + + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${ENUM_VALUES} + + LastTest = ${LAST_ENUM} +//----------------------------------------------------------------------------- +//clang-format on +}; + +IPDLUnitTestType IPDLUnitTestFromString(const char* const aString) { + if (!aString) return static_cast<IPDLUnitTestType>(0); +// clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${STRING_TO_ENUMS} +//----------------------------------------------------------------------------- + // clang-format on + else return static_cast<IPDLUnitTestType>(0); +} + +IPDLUnitTestType IPDLUnitTest() { + return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName()); +} + +} // namespace + +//----------------------------------------------------------------------------- +// 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); + MOZ_CRASH("can't continue"); + } + gIPDLUnitTestName = testString; + + // Check whether this test is enabled for processes: + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_ENABLED_CASES_PROC} +//----------------------------------------------------------------------------- + // clang-format on + + 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) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_MAIN_CASES_PROC} +//----------------------------------------------------------------------------- + // clang-format on + + 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); + MOZ_CRASH("can't continue"); + } + gIPDLUnitTestName = testString; + + // Check whether this test is enabled for threads: + switch (test) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_ENABLED_CASES_THREAD} +//----------------------------------------------------------------------------- + // clang-format on + + 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) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_MAIN_CASES_THREAD} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } +} + +void DeleteParentActor() { + if (!gParentActor) return; + + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${PARENT_DELETE_CASES} +//----------------------------------------------------------------------------- + // clang-format on + 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 + gSubprocess->Destroy(); + gSubprocess = nullptr; + uiLoop->PostTask(NewRunnableFunction("QuitXPCOM", QuitXPCOM)); +} + +void DeferredParentShutdown() { + // ping to DeleteSubprocess + XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction( + "DeleteSubprocess", 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", TryThreadedShutdown)); + } else { + // defer "real" shutdown to avoid *Channel::Close() racing with the + // deletion of the subprocess + MessageLoop::current()->PostTask( + NewRunnableFunction("DeferredParentShutdown", DeferredParentShutdown)); + } +} + +static void ChildDie() { + DeleteChildActor(); + XRE_ShutdownChildProcess(); +} + +void QuitChild() { + if (gChildThread) { // Threaded-mode test + gParentMessageLoop->PostTask( + NewRunnableFunction("ChildCompleted", ChildCompleted)); + } else { // Process-mode test + MessageLoop::current()->PostTask(NewRunnableFunction("ChildDie", ChildDie)); + } +} + +} // namespace _ipdltest +} // namespace mozilla + +//----------------------------------------------------------------------------- +// child process only + +namespace mozilla { +namespace _ipdltest { + +void DeleteChildActor() { + if (!gChildActor) return; + + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${CHILD_DELETE_CASES} +//----------------------------------------------------------------------------- + // clang-format on + default: + ::mozilla::_ipdltest::fail("???"); + } +} + +void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid, + MessageLoop* worker) { + switch (IPDLUnitTest()) { + // clang-format off +//----------------------------------------------------------------------------- +//===== TEMPLATED ===== +${CHILD_INIT_CASES} +//----------------------------------------------------------------------------- + // clang-format on + + default: + fail("not reached"); + return; // unreached + } +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/Makefile.in b/ipc/ipdl/test/cxx/Makefile.in new file mode 100644 index 0000000000..b32533a648 --- /dev/null +++ b/ipc/ipdl/test/cxx/Makefile.in @@ -0,0 +1,45 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +IPDLTESTSRCS = $(filter Test%,$(CPPSRCS)) +IPDLTESTS = $(IPDLTESTSRCS:.cpp=) + +EXTRA_PROTOCOLS = \ + TestEndpointBridgeSub \ + $(NULL) + +IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS))) + +TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp +GENTESTER := $(srcdir)/genIPDLUnitTests.py + +include $(topsrcdir)/config/rules.mk + + +IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX) + +IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS) + $(PYTHON3) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@ + +check-proc:: + @$(EXIT_ON_ERROR) \ + for test in $(IPDLTESTS); do \ + $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \ + done + +check-thread:: + @$(EXIT_ON_ERROR) \ + for test in $(IPDLTESTS); do \ + $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \ + done + +check:: check-proc check-thread + +check-valgrind:: + @$(EXIT_ON_ERROR) \ + for test in $(IPDLTESTS); do \ + $(RUN_TEST_PROGRAM) -g -d \ + valgrind -a '--leak-check=full --trace-children=yes -q' \ + $(IPDLUNITTEST_BIN) $$test ; \ + done diff --git a/ipc/ipdl/test/cxx/PTestActorPunning.ipdl b/ipc/ipdl/test/cxx/PTestActorPunning.ipdl new file mode 100644 index 0000000000..0aec430d9f --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestActorPunning.ipdl @@ -0,0 +1,28 @@ + +include protocol PTestActorPunningPunned; +include protocol PTestActorPunningSub; +include "mozilla/_ipdltest/IPDLUnitTestUtils.h"; +include "mozilla/_ipdltest/TestActorPunning.h"; + +using struct mozilla::_ipdltest::Bad from "mozilla/_ipdltest/IPDLUnitTestUtils.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestActorPunningChild", ParentImpl="TestActorPunningParent"] +protocol PTestActorPunning { + manages PTestActorPunningPunned; + manages PTestActorPunningSub; + +child: + async Start(); + +parent: + async PTestActorPunningPunned(); + async PTestActorPunningSub(); + async Pun(PTestActorPunningSub a, Bad bad); + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl b/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl new file mode 100644 index 0000000000..5cca8a8ab5 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl @@ -0,0 +1,18 @@ + +include protocol PTestActorPunning; + +include "mozilla/_ipdltest/TestActorPunning.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestActorPunningPunnedChild", ParentImpl="TestActorPunningPunnedParent"] +protocol PTestActorPunningPunned { + manager PTestActorPunning; + +child: + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltes diff --git a/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl b/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl new file mode 100644 index 0000000000..0cb522255c --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl @@ -0,0 +1,19 @@ + +include protocol PTestActorPunning; + +include "mozilla/_ipdltest/TestActorPunning.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestActorPunningSubChild", ParentImpl="TestActorPunningSubParent"] +protocol PTestActorPunningSub { + manager PTestActorPunning; + +child: + async Bad(); + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltes diff --git a/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl b/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl new file mode 100644 index 0000000000..42ef17d1e8 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl @@ -0,0 +1,20 @@ +include "mozilla/_ipdltest/TestAsyncReturns.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestAsyncReturnsChild", ParentImpl="TestAsyncReturnsParent"] +protocol PTestAsyncReturns { + +child: + async Ping() returns (bool one); + async NoReturn() returns (bool unused); + +parent: + async Pong() returns (uint32_t param1, uint32_t param2); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestBadActor.ipdl b/ipc/ipdl/test/cxx/PTestBadActor.ipdl new file mode 100644 index 0000000000..991e6eb945 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestBadActor.ipdl @@ -0,0 +1,21 @@ +include protocol PTestBadActorSub; + +include "mozilla/_ipdltest/TestBadActor.h"; + +namespace mozilla { +namespace _ipdltest { + +// Test that a parent sending a reentrant __delete__ message +// is not killed if a child's message races with the reply. + +[ManualDealloc, ChildImpl="TestBadActorChild", ParentImpl="TestBadActorParent"] +intr protocol PTestBadActor { + manages PTestBadActorSub; + +child: + async PTestBadActorSub(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl b/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl new file mode 100644 index 0000000000..aadd8b6739 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl @@ -0,0 +1,20 @@ +include protocol PTestBadActor; + +include "mozilla/_ipdltest/TestBadActor.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestBadActorSubChild", ParentImpl="TestBadActorSubParent"] +intr protocol PTestBadActorSub { + manager PTestBadActor; + +child: + [LegacyIntr] intr __delete__(); + +parent: + async Ping(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestCancel.ipdl b/ipc/ipdl/test/cxx/PTestCancel.ipdl new file mode 100644 index 0000000000..4ad902e8e1 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestCancel.ipdl @@ -0,0 +1,39 @@ +include "mozilla/_ipdltest/TestCancel.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestCancelChild", ParentImpl="TestCancelParent"] +sync protocol PTestCancel +{ +// Test1 +child: + [Nested=inside_sync] sync Test1_1(); +parent: + async Done1(); + +// Test2 +child: + async Start2(); + [Nested=inside_sync] sync Test2_2(); +parent: + sync Test2_1(); + +// Test3 +child: + [Nested=inside_sync] sync Test3_1(); +parent: + async Start3(); + [Nested=inside_sync] sync Test3_2(); + +parent: + async Done(); + +child: + [Nested=inside_sync] sync CheckChild() returns (uint32_t reply); +parent: + [Nested=inside_sync] sync CheckParent() returns (uint32_t reply); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl b/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl new file mode 100644 index 0000000000..43d955f1c7 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl @@ -0,0 +1,20 @@ +include "mozilla/_ipdltest/TestCrashCleanup.h"; + +// See bug 538586: if the top-level protocol's actor is deleted before +// the "connection error" notification comes in from the IO thread, +// IPDL teardown never occurs, even if Channel::Close() is called +// after the error. + +namespace mozilla { +namespace _ipdltest { + +// NB: needs to be RPC so that the parent blocks on the child's crash. +[ManualDealloc, ChildImpl="TestCrashCleanupChild", ParentImpl="TestCrashCleanupParent"] +intr protocol PTestCrashCleanup { +child: + [LegacyIntr] intr DIEDIEDIE(); + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestDataStructures.ipdl b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl new file mode 100644 index 0000000000..64b6970666 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl @@ -0,0 +1,109 @@ +include protocol PTestDataStructuresSub; +include PTestDataStructuresCommon; + +include "mozilla/GfxMessageUtils.h"; +include "mozilla/_ipdltest/TestDataStructures.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestDataStructuresChild", ParentImpl="TestDataStructuresParent"] +sync protocol PTestDataStructures { + manages PTestDataStructuresSub; + +child: + async PTestDataStructuresSub(int i); + + async Start(); + +parent: + async __delete__(); + + sync Test1(int[] i1) + returns (int[] o1); + + sync Test2(PTestDataStructuresSub[] i1) + returns (PTestDataStructuresSub[] o1); + + sync Test3(IntDouble i1, + IntDouble i2) + returns (IntDouble o1, + IntDouble o2); + + sync Test4(IntDouble[] i1) + returns (IntDouble[] o1); + + sync Test5(IntDoubleArrays i1, + IntDoubleArrays i2, + IntDoubleArrays i3) + returns (IntDoubleArrays o1, + IntDoubleArrays o2, + IntDoubleArrays o3); + + sync Test6(IntDoubleArrays[] i1) + returns (IntDoubleArrays[] o1); + + sync Test7_0(ActorWrapper a1) + returns (ActorWrapper o1); + + sync Test7(Actors i1, + Actors i2, + Actors i3) + returns (Actors o1, + Actors o2, + Actors o3); + + sync Test8(Actors[] i1) + returns (Actors[] o1); + + sync Test9(Unions i1, + Unions i2, + Unions i3, + Unions i4) + returns (Unions o1, + Unions o2, + Unions o3, + Unions o4); + + sync Test10(Unions[] i1) + returns (Unions[] o1); + + sync Test11(SIntDouble i) + returns (SIntDouble o); + + sync Test12(SIntDoubleArrays i) + returns (SIntDoubleArrays o); + + sync Test13(SActors i) + returns (SActors o); + + sync Test14(Structs i) + returns (Structs o); + + sync Test15(WithStructs i1, + WithStructs i2, + WithStructs i3, + WithStructs i4, + WithStructs i5) + returns (WithStructs o1, + WithStructs o2, + WithStructs o3, + WithStructs o4, + WithStructs o5); + + sync Test16(WithUnions i) + returns (WithUnions o); + + sync Test17(Op[] ops); + + // test that the ParamTraits<nsTArray>::Read() workaround for + // nsTArray's incorrect memmove() semantics works properly + // (nsIntRegion isn't memmove()able) + sync Test18(nsIntRegion[] ops); + + sync Dummy(ShmemUnion su) returns (ShmemUnion rsu); +}; + +} // namespace _ipdltest +} // namespace mozilla + diff --git a/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh b/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh new file mode 100644 index 0000000000..39d7f482b3 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh @@ -0,0 +1,107 @@ +include protocol PTestDataStructuresSub; + +using struct mozilla::null_t from "mozilla/ipc/IPCCore.h"; +using nsIntRegion from "nsRegion.h"; + +namespace mozilla { +namespace _foo { + +union IntDouble { + int; + double; +}; + +struct SIntDouble { + int i; + double d; +}; + +union IntDoubleArrays { + int; + int[]; + double[]; +}; + +struct SIntDoubleArrays { + int i; + int[] ai; + double[] ad; +}; + +struct ActorWrapper { + PTestDataStructuresSub actor; +}; + +union Actors { + int; + int[]; + PTestDataStructuresSub[]; +}; + +struct SActors { + int i; + int[] ai; + PTestDataStructuresSub[] ap; +}; + +union Unions { + int; + int[]; + PTestDataStructuresSub[]; + Actors[]; +}; + +struct Structs { + int i; + int[] ai; + PTestDataStructuresSub[] ap; + SActors[] aa; +}; + +union WithStructs { + int; + int[]; + PTestDataStructuresSub[]; + SActors[]; + Structs[]; +}; + +struct WithUnions { + int i; + int[] ai; + PTestDataStructuresSub[] ap; + Actors[] aa; + Unions[] au; +}; + +struct CommonAttrs { bool dummy; }; +struct FooAttrs { int dummy; }; +struct BarAttrs { float dummy; }; +union SpecificAttrs { + FooAttrs; + BarAttrs; +}; +struct Attrs { + CommonAttrs common; + SpecificAttrs specific; +}; +struct SetAttrs { + PTestDataStructuresSub x; + Attrs attrs; +}; +union Op { null_t; SetAttrs; }; + +struct ShmemStruct { + int i; + Shmem mem; +}; + +union ShmemUnion { + int; + Shmem; +}; + +struct Empty { }; + +} // namespace _foo +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl b/ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl new file mode 100644 index 0000000000..4f546a8d29 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl @@ -0,0 +1,18 @@ +include PTestDataStructuresCommon; +include protocol PTestDataStructures; + +include "mozilla/_ipdltest/TestDataStructures.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestDataStructuresSub", ParentImpl="TestDataStructuresSub"] +sync protocol PTestDataStructuresSub { + manager PTestDataStructures; + +parent: + sync __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestDemon.ipdl b/ipc/ipdl/test/cxx/PTestDemon.ipdl new file mode 100644 index 0000000000..f5af2396e6 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDemon.ipdl @@ -0,0 +1,24 @@ +include "mozilla/_ipdltest/TestDemon.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestDemonChild", ParentImpl="TestDemonParent"] +sync protocol PTestDemon +{ +child: + async Start(); + +both: + async AsyncMessage(int n); + [Nested=inside_sync] sync HiPrioSyncMessage(); + +parent: + sync SyncMessage(int n); + + [Nested=inside_cpow] async UrgentAsyncMessage(int n); + [Nested=inside_cpow] sync UrgentSyncMessage(int n); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestDesc.ipdl b/ipc/ipdl/test/cxx/PTestDesc.ipdl new file mode 100644 index 0000000000..d18d2d8598 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDesc.ipdl @@ -0,0 +1,24 @@ +include protocol PTestDescSub; +include protocol PTestDescSubsub; + +include "mozilla/_ipdltest/TestDesc.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestDescChild", ParentImpl="TestDescParent"] +intr protocol PTestDesc { + manages PTestDescSub; +child: + [LegacyIntr] intr PTestDescSub(nullable PTestDescSubsub dummy); + + async Test(PTestDescSubsub a); + + async __delete__(); + +parent: + async Ok(PTestDescSubsub a); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestDescSub.ipdl b/ipc/ipdl/test/cxx/PTestDescSub.ipdl new file mode 100644 index 0000000000..a05451c639 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDescSub.ipdl @@ -0,0 +1,21 @@ +include protocol PTestDesc; +include protocol PTestDescSubsub; + +include "mozilla/_ipdltest/TestDesc.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestDescSubChild", ParentImpl="TestDescSubParent"] +intr protocol PTestDescSub { + manager PTestDesc; + manages PTestDescSubsub; + +child: + async __delete__(); + + [LegacyIntr] intr PTestDescSubsub(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl b/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl new file mode 100644 index 0000000000..542a03e2d2 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl @@ -0,0 +1,18 @@ + +include protocol PTestDescSub; + +include "mozilla/_ipdltest/TestDesc.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestDescSubsubChild", ParentImpl="TestDescSubsubParent"] +intr protocol PTestDescSubsub { + manager PTestDescSub; + +child: + [LegacyIntr] intr __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl new file mode 100644 index 0000000000..c51967b1fa --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +include protocol PTestEndpointBridgeMainSub; +include protocol PTestEndpointBridgeSub; + +include "mozilla/_ipdltest/TestEndpointBridgeMain.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestEndpointBridgeMainChild", ParentImpl="TestEndpointBridgeMainParent"] +protocol PTestEndpointBridgeMain { + +child: + async Start(); + +parent: + async Bridged(Endpoint<PTestEndpointBridgeMainSubParent> endpoint); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl new file mode 100644 index 0000000000..e899fca7aa --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +include protocol PTestEndpointBridgeMain; +include protocol PTestEndpointBridgeSub; + +include "mozilla/_ipdltest/TestEndpointBridgeMain.h"; + +namespace mozilla { +namespace _ipdltest { + +// (Bridge protocols can have different semantics than the endpoints +// they bridge) +[ManualDealloc, ChildImpl="TestEndpointBridgeMainSubChild", ParentImpl="TestEndpointBridgeMainSubParent"] +intr protocol PTestEndpointBridgeMainSub { +child: + async Hi(); + [LegacyIntr] intr HiRpc(); + +parent: + async Hello(); + sync HelloSync(); + [LegacyIntr] intr HelloRpc(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl new file mode 100644 index 0000000000..ab12e3bdb5 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +include protocol PTestEndpointBridgeMainSub; + +include "mozilla/_ipdltest/TestEndpointBridgeMain.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestEndpointBridgeSubChild", ParentImpl="TestEndpointBridgeSubParent"] +protocol PTestEndpointBridgeSub { +child: + async Ping(); + + async Bridged(Endpoint<PTestEndpointBridgeMainSubChild> endpoint); + +parent: + async BridgeEm(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl b/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl new file mode 100644 index 0000000000..6cb20bf8eb --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +include protocol PTestEndpointOpensOpened; + +include "mozilla/_ipdltest/TestEndpointOpens.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestEndpointOpensChild", ParentImpl="TestEndpointOpensParent"] +protocol PTestEndpointOpens { +child: + async Start(); + +parent: + async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint); + + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl b/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl new file mode 100644 index 0000000000..7f72828c30 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +include "mozilla/_ipdltest/TestEndpointOpens.h"; + +namespace mozilla { +namespace _ipdltest2 { + +// (Opens protocols can have different semantics than the endpoints +// that opened them) +[ManualDealloc, ChildImpl="TestEndpointOpensOpenedChild", ParentImpl="TestEndpointOpensOpenedParent"] +intr protocol PTestEndpointOpensOpened { +child: + async Hi(); + [LegacyIntr] intr HiRpc(); + +parent: + async Hello(); + sync HelloSync(); + [LegacyIntr] intr HelloRpc(); + async __delete__(); +}; + + +} // namespace mozilla +} // namespace _ipdltest2 diff --git a/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl new file mode 100644 index 0000000000..0144f66dba --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl @@ -0,0 +1,17 @@ +include protocol PTestFailedCtorSub; + +include "mozilla/_ipdltest/TestFailedCtor.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestFailedCtorChild", ParentImpl="TestFailedCtorParent"] +intr protocol PTestFailedCtor { + manages PTestFailedCtorSub; +child: + [LegacyIntr] intr PTestFailedCtorSub(); + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl new file mode 100644 index 0000000000..97bc4d4bf8 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl @@ -0,0 +1,21 @@ +include protocol PTestFailedCtor; +include protocol PTestFailedCtorSubsub; + +include "mozilla/_ipdltest/TestFailedCtor.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestFailedCtorSubChild", ParentImpl="TestFailedCtorSubParent"] +intr protocol PTestFailedCtorSub { + manager PTestFailedCtor; + manages PTestFailedCtorSubsub; + +parent: + async PTestFailedCtorSubsub(); + sync Sync(); + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl new file mode 100644 index 0000000000..84cb2a0eb8 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl @@ -0,0 +1,18 @@ + +include protocol PTestFailedCtorSub; + +include "mozilla/_ipdltest/TestFailedCtor.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestFailedCtorSubsub", ParentImpl="TestFailedCtorSubsub"] +intr protocol PTestFailedCtorSubsub { + manager PTestFailedCtorSub; + +parent: + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestHandle.ipdl b/ipc/ipdl/test/cxx/PTestHandle.ipdl new file mode 100644 index 0000000000..b0a65f69c0 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestHandle.ipdl @@ -0,0 +1,17 @@ +include protocol PTestJSON; + +include "mozilla/_ipdltest/TestJSON.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestHandleChild", ParentImpl="TestHandleParent"] +protocol PTestHandle { + manager PTestJSON; + +child: + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestHangs.ipdl b/ipc/ipdl/test/cxx/PTestHangs.ipdl new file mode 100644 index 0000000000..cadc1eda2e --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestHangs.ipdl @@ -0,0 +1,22 @@ + +include "mozilla/_ipdltest/TestHangs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestHangsChild", ParentImpl="TestHangsParent"] +intr protocol PTestHangs { +both: + [LegacyIntr] intr StackFrame(); + +parent: + async Nonce(); + +child: + async Start(); + [LegacyIntr] intr Hang(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl new file mode 100644 index 0000000000..877ba427b6 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl @@ -0,0 +1,21 @@ +include "mozilla/_ipdltest/TestHighestPrio.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestHighestPrioChild", ParentImpl="TestHighestPrioParent"] +sync protocol PTestHighestPrio +{ +parent: + [Nested=inside_cpow] async Msg1(); + [Nested=inside_sync] sync Msg2(); + [Nested=inside_cpow] async Msg3(); + [Nested=inside_cpow] sync Msg4(); + +child: + async Start(); + [Nested=inside_sync] sync StartInner(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh new file mode 100644 index 0000000000..a81fcdee46 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh @@ -0,0 +1,15 @@ +include protocol PTestIndirectProtocolParamSecond;
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct IndirectParamStruct {
+ PTestIndirectProtocolParamSecond actor;
+};
+
+union IndirectParamUnion {
+ IndirectParamStruct;
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl new file mode 100644 index 0000000000..5364d79ffb --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl @@ -0,0 +1,20 @@ +include protocol PTestIndirectProtocolParamManage; +// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is +// already included in PTestIndirectProtocolParam.ipdlh +include protocol PTestIndirectProtocolParamSecond; +include PTestIndirectProtocolParam; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +sync protocol PTestIndirectProtocolParamFirst { + manager PTestIndirectProtocolParamManage; +parent: + sync Test(IndirectParamUnion actor); +both: + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl new file mode 100644 index 0000000000..8d3c6f81b1 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl @@ -0,0 +1,18 @@ +include protocol PTestIndirectProtocolParamFirst; +include protocol PTestIndirectProtocolParamSecond; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +sync protocol PTestIndirectProtocolParamManage { + manages PTestIndirectProtocolParamFirst; + manages PTestIndirectProtocolParamSecond; +both: + async PTestIndirectProtocolParamFirst(); + async PTestIndirectProtocolParamSecond(); + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl new file mode 100644 index 0000000000..27545ca2cb --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl @@ -0,0 +1,14 @@ +include protocol PTestIndirectProtocolParamManage; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +sync protocol PTestIndirectProtocolParamSecond { + manager PTestIndirectProtocolParamManage; +both: + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl b/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl new file mode 100644 index 0000000000..ab6754cc1b --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl @@ -0,0 +1,14 @@ +include "mozilla/_ipdltest/TestInterruptErrorCleanup.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestInterruptErrorCleanupChild", ParentImpl="TestInterruptErrorCleanupParent"] +intr protocol PTestInterruptErrorCleanup { +child: + [LegacyIntr] intr Error(); + [LegacyIntr] intr __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl b/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl new file mode 100644 index 0000000000..aa66966938 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl @@ -0,0 +1,27 @@ +include "mozilla/_ipdltest/TestInterruptRaces.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestInterruptRacesChild", ParentImpl="TestInterruptRacesParent"] +intr protocol PTestInterruptRaces { +both: + [LegacyIntr] intr Race() returns (bool hasReply); + [LegacyIntr] intr StackFrame() returns (); + [LegacyIntr] intr StackFrame3() returns (); + +parent: + sync StartRace(); + [LegacyIntr] intr Parent(); + sync GetAnsweredParent() returns (bool answeredParent); + +child: + async Start(); + async Wakeup(); + async Wakeup3(); + [LegacyIntr] intr Child(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl b/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl new file mode 100644 index 0000000000..84bc6f0a97 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl @@ -0,0 +1,19 @@ +include "mozilla/_ipdltest/TestInterruptShutdownRace.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestInterruptShutdownRaceChild", ParentImpl="TestInterruptShutdownRaceParent"] +intr protocol PTestInterruptShutdownRace { +parent: + sync StartDeath(); + async Orphan(); + +child: + async Start(); + [LegacyIntr] intr Exit(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestJSON.ipdl b/ipc/ipdl/test/cxx/PTestJSON.ipdl new file mode 100644 index 0000000000..c785abe77a --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestJSON.ipdl @@ -0,0 +1,49 @@ +include protocol PTestHandle; + +include "mozilla/_ipdltest/TestJSON.h"; + +using struct mozilla::void_t from "mozilla/ipc/IPCCore.h"; +using struct mozilla::null_t from "mozilla/ipc/IPCCore.h"; + +namespace mozilla { +namespace _ipdltest { + +union Key { +// int; +// double; + nsString; +}; + +struct KeyValue { + Key key; + JSONVariant value; +}; + +union JSONVariant { + void_t; + null_t; + bool; + int; + double; + nsString; + PTestHandle; + KeyValue[]; + JSONVariant[]; +}; + +[ManualDealloc, ChildImpl="TestJSONChild", ParentImpl="TestJSONParent"] +sync protocol PTestJSON { + manages PTestHandle; + +child: + async Start(); + +parent: + async PTestHandle(); + sync Test(JSONVariant i) + returns (JSONVariant o); + async __delete__(); +}; + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestLatency.ipdl b/ipc/ipdl/test/cxx/PTestLatency.ipdl new file mode 100644 index 0000000000..d868d119a2 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestLatency.ipdl @@ -0,0 +1,28 @@ +include "mozilla/_ipdltest/TestLatency.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestLatencyChild", ParentImpl="TestLatencyParent"] +intr protocol PTestLatency { + +child: + async __delete__(); + async Ping(); + async Ping5(); + [LegacyIntr] intr Rpc(); + async Spam(); + [LegacyIntr] intr Synchro(); + [Compress] async CompressedSpam(uint32_t seqno); + [LegacyIntr] intr Synchro2() returns (uint32_t lastSeqno, + uint32_t numMessagesDispatched); + +parent: + async Pong(); + async Pong5(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl b/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl new file mode 100644 index 0000000000..6f8a0e1187 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl @@ -0,0 +1,22 @@ +include protocol PTestManyChildAllocsSub; + +include "mozilla/_ipdltest/TestManyChildAllocs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestManyChildAllocsChild", ParentImpl="TestManyChildAllocsParent"] +protocol PTestManyChildAllocs { + manages PTestManyChildAllocsSub; + +child: + async Go(); // start allocating + +parent: + async Done(); + + async PTestManyChildAllocsSub(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl b/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl new file mode 100644 index 0000000000..e20c2badfd --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl @@ -0,0 +1,22 @@ +include protocol PTestManyChildAllocs; + +include "mozilla/_ipdltest/TestManyChildAllocs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestManyChildAllocsSubChild", ParentImpl="TestManyChildAllocsSubParent"] +protocol PTestManyChildAllocsSub { + manager PTestManyChildAllocs; + +child: + async __delete__(); + +parent: + async Hello(); + + // empty +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl new file mode 100644 index 0000000000..65272fa991 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl @@ -0,0 +1,25 @@ +include protocol PTestMultiMgrsLeft; +include protocol PTestMultiMgrsRight; + +include "mozilla/_ipdltest/TestMultiMgrs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestMultiMgrsChild", ParentImpl="TestMultiMgrsParent"] +protocol PTestMultiMgrs { + manages PTestMultiMgrsLeft; + manages PTestMultiMgrsRight; + +parent: + async OK(); + +child: + async PTestMultiMgrsLeft(); + async PTestMultiMgrsRight(); + async Check(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl new file mode 100644 index 0000000000..be85b1547b --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl @@ -0,0 +1,18 @@ +include protocol PTestMultiMgrsLeft; +include protocol PTestMultiMgrsRight; + +include "mozilla/_ipdltest/TestMultiMgrs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestMultiMgrsBottomChild", ParentImpl="TestMultiMgrsBottomParent"] +protocol PTestMultiMgrsBottom { + manager PTestMultiMgrsLeft or PTestMultiMgrsRight; + +child: + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl new file mode 100644 index 0000000000..3796ff315e --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl @@ -0,0 +1,21 @@ +include protocol PTestMultiMgrs; +include protocol PTestMultiMgrsBottom; + +include "mozilla/_ipdltest/TestMultiMgrs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestMultiMgrsLeftChild", ParentImpl="TestMultiMgrsLeftParent"] +protocol PTestMultiMgrsLeft { + manager PTestMultiMgrs; + + manages PTestMultiMgrsBottom; + +child: + async PTestMultiMgrsBottom(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl new file mode 100644 index 0000000000..174ada5ca3 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl @@ -0,0 +1,21 @@ +include protocol PTestMultiMgrs; +include protocol PTestMultiMgrsBottom; + +include "mozilla/_ipdltest/TestMultiMgrs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestMultiMgrsRightChild", ParentImpl="TestMultiMgrsRightParent"] +protocol PTestMultiMgrsRight { + manager PTestMultiMgrs; + + manages PTestMultiMgrsBottom; + +child: + async PTestMultiMgrsBottom(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl b/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl new file mode 100644 index 0000000000..168461ab41 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl @@ -0,0 +1,22 @@ + +include "mozilla/_ipdltest/TestNestedLoops.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestNestedLoopsChild", ParentImpl="TestNestedLoopsParent"] +intr protocol PTestNestedLoops { + +child: + async Start(); + [LegacyIntr] intr R(); + async __delete__(); + +parent: + async Nonce(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestPaintThread.ipdl b/ipc/ipdl/test/cxx/PTestPaintThread.ipdl new file mode 100644 index 0000000000..00d46c9757 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestPaintThread.ipdl @@ -0,0 +1,15 @@ +include "mozilla/_ipdltest/TestOffMainThreadPainting.h"; + +namespace mozilla { +namespace _ipdltest { + +// This is supposed to be analagous to PPaintingBridge. +[ManualDealloc, ChildImpl="TestPaintThreadChild", ParentImpl="TestPaintThreadParent"] +sync protocol PTestPaintThread +{ +parent: + sync FinishedPaint(uint64_t aTxnId); +}; + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestPriority.ipdl b/ipc/ipdl/test/cxx/PTestPriority.ipdl new file mode 100644 index 0000000000..8b85368072 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestPriority.ipdl @@ -0,0 +1,24 @@ +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +sync protocol PTestPriority { +parent: + [Priority=input] async PMsg1(); + [Priority=input] sync PMsg2(); + [Priority=vsync] async PMsg3(); + [Priority=vsync] sync PMsg4(); + [Priority=mediumhigh] async PMsg5(); + [Priority=mediumhigh] sync PMsg6(); + [Priority=control] async PMsg7(); + [Priority=control] sync PMsg8(); + +child: + [Priority=input] async CMsg1(); + [Priority=vsync] async CMsg2(); + [Priority=mediumhigh] async CMsg3(); + [Priority=control] async CMsg4(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestRPC.ipdl b/ipc/ipdl/test/cxx/PTestRPC.ipdl new file mode 100644 index 0000000000..4d459eeb03 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl @@ -0,0 +1,24 @@ +include "mozilla/_ipdltest/TestRPC.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestRPCChild", ParentImpl="TestRPCParent"] +sync protocol PTestRPC +{ +parent: + [Nested=inside_sync] sync Test1_Start() returns (uint32_t result); + [Nested=inside_sync] sync Test1_InnerEvent() returns (uint32_t result); + async Test2_Start(); + [Nested=inside_sync] sync Test2_OutOfOrder(); + +child: + async Start(); + [Nested=inside_sync] sync Test1_InnerQuery() returns (uint32_t result); + [Nested=inside_sync] sync Test1_NoReenter() returns (uint32_t result); + [Nested=inside_sync] sync Test2_FirstUrgent(); + [Nested=inside_sync] sync Test2_SecondUrgent(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl new file mode 100644 index 0000000000..125919f9af --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl @@ -0,0 +1,23 @@ +include "mozilla/_ipdltest/TestRaceDeadlock.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestRaceDeadlockChild", ParentImpl="TestRaceDeadlockParent"] +intr protocol PTestRaceDeadlock { +both: + async StartRace(); + +parent: + [LegacyIntr] intr Lose(); + +child: + [LegacyIntr] intr Win(); + [LegacyIntr] intr Rpc(); + async __delete__(); + +/* Tests that race resolution does not cause deadlocks */ +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl b/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl new file mode 100644 index 0000000000..f165fa1cea --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl @@ -0,0 +1,22 @@ +include "mozilla/_ipdltest/TestRaceDeferral.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestRaceDeferralChild", ParentImpl="TestRaceDeferralParent"] +intr protocol PTestRaceDeferral { +parent: + [LegacyIntr] intr Lose(); + +child: + async StartRace(); + [LegacyIntr] intr Win(); + [LegacyIntr] intr Rpc(); + async __delete__(); + +// Test that messages deferred due to race resolution are +// re-considered when the winner makes later RPCs +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl b/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl new file mode 100644 index 0000000000..37b7973e6d --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl @@ -0,0 +1,20 @@ +include "mozilla/_ipdltest/TestRacyInterruptReplies.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestRacyInterruptRepliesChild", ParentImpl="TestRacyInterruptRepliesParent"] +intr protocol PTestRacyInterruptReplies { +child: + [LegacyIntr] intr R_() returns (int replyNum); + async _A(); + async ChildTest(); + async __delete__(); + +parent: + [LegacyIntr] intr _R() returns (int replyNum); + async A_(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl b/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl new file mode 100644 index 0000000000..b9579cef24 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl @@ -0,0 +1,23 @@ +include "mozilla/_ipdltest/TestRacyReentry.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestRacyReentryChild", ParentImpl="TestRacyReentryParent"] +intr protocol PTestRacyReentry { + +parent: + [LegacyIntr] intr E(); + async __delete__(); + +child: + async Start(); + + async N(); + [LegacyIntr] intr H(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl b/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl new file mode 100644 index 0000000000..6256eca9db --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl @@ -0,0 +1,30 @@ +include "mozilla/_ipdltest/TestRacyUndefer.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestRacyUndeferChild", ParentImpl="TestRacyUndeferParent"] +intr protocol PTestRacyUndefer { + +child: + async Start(); + + async AwakenSpam(); + async AwakenRaceWinTwice(); + + [LegacyIntr] intr Race(); + + async __delete__(); + +parent: + + [LegacyIntr] intr Spam(); + [LegacyIntr] intr RaceWinTwice(); + + async Done(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSanity.ipdl b/ipc/ipdl/test/cxx/PTestSanity.ipdl new file mode 100644 index 0000000000..3b3e130d4a --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSanity.ipdl @@ -0,0 +1,21 @@ + +include "mozilla/_ipdltest/TestSanity.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestSanityChild", ParentImpl="TestSanityParent"] +protocol PTestSanity { + +child: + async Ping(int zero, float zeroPtFive, int8_t dummy); + async __delete__(); + +parent: + async Pong(int one, float zeroPtTwoFive, uint8_t dummy); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSelfManage.ipdl b/ipc/ipdl/test/cxx/PTestSelfManage.ipdl new file mode 100644 index 0000000000..19f81a5ae7 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSelfManage.ipdl @@ -0,0 +1,21 @@ +include protocol PTestSelfManageRoot; + +include "mozilla/_ipdltest/TestSelfManageRoot.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestSelfManageChild", ParentImpl="TestSelfManageParent"] +protocol PTestSelfManage { + manager PTestSelfManageRoot or PTestSelfManage; + manages PTestSelfManage; + +child: + async PTestSelfManage(); + async __delete__(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl b/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl new file mode 100644 index 0000000000..29953228af --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl @@ -0,0 +1,20 @@ +include protocol PTestSelfManage; + +include "mozilla/_ipdltest/TestSelfManageRoot.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestSelfManageRootChild", ParentImpl="TestSelfManageRootParent"] +protocol PTestSelfManageRoot { + manages PTestSelfManage; + +child: + async PTestSelfManage(); + async __delete__(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestShmem.ipdl b/ipc/ipdl/test/cxx/PTestShmem.ipdl new file mode 100644 index 0000000000..7eb6dfdc36 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestShmem.ipdl @@ -0,0 +1,17 @@ +include "mozilla/_ipdltest/TestShmem.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestShmemChild", ParentImpl="TestShmemParent"] +protocol PTestShmem { +child: + async Give(Shmem mem, Shmem unsafe, uint32_t expectedSize); + +parent: + async Take(Shmem mem, Shmem unsafe, uint32_t expectedSize); + async __delete__(); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestShutdown.ipdl b/ipc/ipdl/test/cxx/PTestShutdown.ipdl new file mode 100644 index 0000000000..e57defa46a --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestShutdown.ipdl @@ -0,0 +1,29 @@ +include protocol PTestShutdownSub; + +include "mozilla/_ipdltest/TestShutdown.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestShutdownChild", ParentImpl="TestShutdownParent"] +intr protocol PTestShutdown { + manages PTestShutdownSub; + +child: + async Start(); + +parent: + // NB: we test deletion and crashing only, not shutdown, because + // crashing is the same code path as shutdown, and other IPDL unit + // tests check shutdown semantics + async PTestShutdownSub(bool expectCrash); + + // Used to synchronize between parent and child, to avoid races + // around flushing socket write queues + sync Sync(); + + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl b/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl new file mode 100644 index 0000000000..e91caca740 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl @@ -0,0 +1,23 @@ +include protocol PTestShutdown; +include protocol PTestShutdownSubsub; + +include "mozilla/_ipdltest/TestShutdown.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestShutdownSubChild", ParentImpl="TestShutdownSubParent"] +intr protocol PTestShutdownSub { + manager PTestShutdown; + manages PTestShutdownSubsub; + +both: + [LegacyIntr] intr StackFrame(); + +parent: + async PTestShutdownSubsub(bool expectParentDeleted); + sync __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl b/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl new file mode 100644 index 0000000000..3b1cc5cb6b --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl @@ -0,0 +1,17 @@ +include protocol PTestShutdownSub; + +include "mozilla/_ipdltest/TestShutdown.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestShutdownSubsubChild", ParentImpl="TestShutdownSubsubParent"] +sync protocol PTestShutdownSubsub { + manager PTestShutdownSub; + +parent: + sync __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestStackHooks.ipdl b/ipc/ipdl/test/cxx/PTestStackHooks.ipdl new file mode 100644 index 0000000000..3026dfbfbe --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestStackHooks.ipdl @@ -0,0 +1,28 @@ +include "mozilla/_ipdltest/TestStackHooks.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestStackHooksChild", ParentImpl="TestStackHooksParent"] +intr protocol PTestStackHooks { +child: + async Start(); + + // These tests are more fruitful running child->parent, because + // children can send |sync| messages +parent: + async Async(); + sync Sync(); + [LegacyIntr] intr Rpc(); + +both: + [LegacyIntr] intr StackFrame(); + +parent: + async __delete__(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSyncError.ipdl b/ipc/ipdl/test/cxx/PTestSyncError.ipdl new file mode 100644 index 0000000000..a4b6d428e8 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSyncError.ipdl @@ -0,0 +1,20 @@ +include "mozilla/_ipdltest/TestSyncError.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestSyncErrorChild", ParentImpl="TestSyncErrorParent"] +sync protocol PTestSyncError { + +child: + async Start(); + +parent: + sync Error(); + async __delete__(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSyncHang.ipdl b/ipc/ipdl/test/cxx/PTestSyncHang.ipdl new file mode 100644 index 0000000000..05521d6ed2 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSyncHang.ipdl @@ -0,0 +1,16 @@ +include "mozilla/_ipdltest/TestSyncHang.h"; + +namespace mozilla { +namespace _ipdltest { + + +[ManualDealloc, ChildImpl="TestSyncHangChild", ParentImpl="TestSyncHangParent"] +protocol PTestSyncHang { + +child: + async UnusedMessage(); +}; + + +} // namespace mozilla +} // namespace _ipdltest diff --git a/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl b/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl new file mode 100644 index 0000000000..807f558dfa --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl @@ -0,0 +1,23 @@ +include "mozilla/_ipdltest/TestSyncWakeup.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, ChildImpl="TestSyncWakeupChild", ParentImpl="TestSyncWakeupParent"] +intr protocol PTestSyncWakeup { +both: + [LegacyIntr] intr StackFrame(); + +child: + async Start(); + async Note1(); + async Note2(); + +parent: + sync Sync1(); + sync Sync2(); + async __delete__(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl b/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl new file mode 100644 index 0000000000..b436dcbbb3 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include "mozilla/_ipdltest/TestUniquePtrIPC.h"; + +namespace mozilla { +namespace _ipdltest { + +struct DummyStruct { + int x; +}; + +[ManualDealloc, ChildImpl="TestUniquePtrIPCChild", ParentImpl="TestUniquePtrIPCParent"] +protocol PTestUniquePtrIPC +{ +child: + async TestMessage(UniquePtr<int> a1, UniquePtr<DummyStruct> a2, + DummyStruct a3, UniquePtr<int> a4); + async TestSendReference(UniquePtr<DummyStruct> a); +}; + +} +} diff --git a/ipc/ipdl/test/cxx/PTestUrgency.ipdl b/ipc/ipdl/test/cxx/PTestUrgency.ipdl new file mode 100644 index 0000000000..7653d12102 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestUrgency.ipdl @@ -0,0 +1,22 @@ +include "mozilla/_ipdltest/TestUrgency.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestUrgencyChild", ParentImpl="TestUrgencyParent"] +sync protocol PTestUrgency +{ +parent: + [Nested=inside_sync] sync Test1() returns (uint32_t result); + async Test2(); + sync Test3() returns (uint32_t result); + sync FinalTest_Begin(); + +child: + async Start(); + [Nested=inside_sync] sync Reply1() returns (uint32_t result); + [Nested=inside_sync] sync Reply2() returns (uint32_t result); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl b/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl new file mode 100644 index 0000000000..2c19a7afe1 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl @@ -0,0 +1,31 @@ +include "mozilla/_ipdltest/TestUrgentHangs.h"; + +namespace mozilla { +namespace _ipdltest { + +[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestUrgentHangsChild", ParentImpl="TestUrgentHangsParent"] +sync protocol PTestUrgentHangs +{ +parent: + [Nested=inside_sync] sync Test1_2(); + + [Nested=inside_sync] sync TestInner(); + [Nested=inside_cpow] sync TestInnerUrgent(); + +child: + [Nested=inside_sync] sync Test1_1(); + [Nested=inside_sync] sync Test1_3(); + + [Nested=inside_sync] sync Test2(); + + [Nested=inside_sync] sync Test3(); + + async Test4(); + [Nested=inside_sync] sync Test4_1(); + + async Test5(); + [Nested=inside_sync] sync Test5_1(); +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/README.txt b/ipc/ipdl/test/cxx/README.txt new file mode 100644 index 0000000000..0fe6c07320 --- /dev/null +++ b/ipc/ipdl/test/cxx/README.txt @@ -0,0 +1,61 @@ +To add a new IPDL C++ unit test, you need to create (at least) the +following files (for a test "TestFoo"): + + - PTestFoo.ipdl, specifying the top-level protocol used for the test + + - TestFoo.h, declaring the top-level parent/child actors used for + the test + + - TestFoo.cpp, defining the top-level actors + + - (make sure all are in the namespace mozilla::_ipdltest) + +Next + + - add PTestFoo.ipdl to ipdl.mk + + - append TestFoo to the variable IPDLTESTS in Makefile.in + +You must define three methods in your |TestFooParent| class: + + - static methods |bool RunTestInProcesses()| and + |bool RunTestInThreads()|. These methods control whether + to execute the test using actors in separate processes and + threads respectively. Generally, both should return true. + + - an instance method |void Main()|. The test harness wil first + initialize the processes or threads, create and open both actors, + and then kick off the test using |Main()|. Make sure you define + it. + +If your test passes its criteria, please call +|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully". + +If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit +ungracefully", preferably by abort()ing. + + +If all goes well, running + + make -C $OBJDIR/ipc/ipdl/test/cxx + +will update the file IPDLUnitTests.cpp (the test launcher), and your +new code will be built automatically. + + +You can launch your new test by invoking one of + + make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests) + make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests) + make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both) + +If you want to launch only your test, run + + cd $OBJDIR/dist/bin + ./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.) + ./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.) + + +For a bare-bones example of adding a test, take a look at +PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity" +is included in ipdl.mk and Makefile.in. diff --git a/ipc/ipdl/test/cxx/TestActorPunning.cpp b/ipc/ipdl/test/cxx/TestActorPunning.cpp new file mode 100644 index 0000000000..5825796f54 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestActorPunning.cpp @@ -0,0 +1,125 @@ +#include "TestActorPunning.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "mozilla/Unused.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +void TestActorPunningParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestActorPunningParent::RecvPun( + PTestActorPunningSubParent* a, const Bad& bad) { + if (a->SendBad()) fail("bad!"); + fail("shouldn't have received this message in the first place"); + return IPC_OK(); +} + +// By default, fatal errors kill the parent process, but this makes it +// hard to test, so instead we use the previous behavior and kill the +// child process. +void TestActorPunningParent::HandleFatalError(const char* aErrorMsg) { + if (!!strcmp(aErrorMsg, "Error deserializing 'PTestActorPunningSubParent'")) { + fail("wrong fatal error"); + } + + ipc::ScopedProcessHandle otherProcessHandle; + if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) { + fail("couldn't open child process"); + } else { + if (!base::KillProcess(otherProcessHandle, 0, false)) { + fail("terminating child process"); + } + } +} + +PTestActorPunningPunnedParent* +TestActorPunningParent::AllocPTestActorPunningPunnedParent() { + return new TestActorPunningPunnedParent(); +} + +bool TestActorPunningParent::DeallocPTestActorPunningPunnedParent( + PTestActorPunningPunnedParent* a) { + delete a; + return true; +} + +PTestActorPunningSubParent* +TestActorPunningParent::AllocPTestActorPunningSubParent() { + return new TestActorPunningSubParent(); +} + +bool TestActorPunningParent::DeallocPTestActorPunningSubParent( + PTestActorPunningSubParent* a) { + delete a; + return true; +} + +//----------------------------------------------------------------------------- +// child + +PTestActorPunningPunnedChild* +TestActorPunningChild::AllocPTestActorPunningPunnedChild() { + return new TestActorPunningPunnedChild(); +} + +bool TestActorPunningChild::DeallocPTestActorPunningPunnedChild( + PTestActorPunningPunnedChild*) { + fail("should have died by now"); + return true; +} + +PTestActorPunningSubChild* +TestActorPunningChild::AllocPTestActorPunningSubChild() { + return new TestActorPunningSubChild(); +} + +bool TestActorPunningChild::DeallocPTestActorPunningSubChild( + PTestActorPunningSubChild*) { + fail("should have died by now"); + return true; +} + +mozilla::ipc::IPCResult TestActorPunningChild::RecvStart() { + SendPTestActorPunningSubConstructor(); + SendPTestActorPunningPunnedConstructor(); + PTestActorPunningSubChild* a = SendPTestActorPunningSubConstructor(); + // We can't assert whether this succeeds or fails, due to race + // conditions. + SendPun(a, Bad()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestActorPunningSubChild::RecvBad() { + fail("things are going really badly right now"); + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla + +namespace IPC { +using namespace mozilla::_ipdltest; +using namespace mozilla::ipc; + +/*static*/ void ParamTraits<Bad>::Write(MessageWriter* aWriter, + const paramType& aParam) { + // Skip past the sentinel for the actor as well as the actor. + int32_t* ptr = aWriter->GetInt32PtrForTest(2 * sizeof(int32_t)); + ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr); + if (ah->mId != -3) + fail("guessed wrong offset (value is %d, should be -3)", ah->mId); + ah->mId = -2; +} + +/*static*/ bool ParamTraits<Bad>::Read(MessageReader* aReader, + paramType* aResult) { + return true; +} + +} // namespace IPC diff --git a/ipc/ipdl/test/cxx/TestActorPunning.h b/ipc/ipdl/test/cxx/TestActorPunning.h new file mode 100644 index 0000000000..cd88106c0c --- /dev/null +++ b/ipc/ipdl/test/cxx/TestActorPunning.h @@ -0,0 +1,100 @@ +#ifndef mozilla__ipdltest_TestActorPunning_h +#define mozilla__ipdltest_TestActorPunning_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestActorPunningParent.h" +#include "mozilla/_ipdltest/PTestActorPunningPunnedParent.h" +#include "mozilla/_ipdltest/PTestActorPunningSubParent.h" +#include "mozilla/_ipdltest/PTestActorPunningChild.h" +#include "mozilla/_ipdltest/PTestActorPunningPunnedChild.h" +#include "mozilla/_ipdltest/PTestActorPunningSubChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestActorPunningParent : public PTestActorPunningParent { + friend class PTestActorPunningParent; + + public: + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + PTestActorPunningPunnedParent* AllocPTestActorPunningPunnedParent(); + bool DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a); + + PTestActorPunningSubParent* AllocPTestActorPunningSubParent(); + bool DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a); + + mozilla::ipc::IPCResult RecvPun(PTestActorPunningSubParent* a, + const Bad& bad); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown == why) fail("should have died from error!"); + passed("ok"); + QuitParent(); + } + + virtual void HandleFatalError(const char* aErrorMsg) override; +}; + +class TestActorPunningPunnedParent : public PTestActorPunningPunnedParent { + public: + TestActorPunningPunnedParent() {} + virtual ~TestActorPunningPunnedParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestActorPunningSubParent : public PTestActorPunningSubParent { + public: + TestActorPunningSubParent() {} + virtual ~TestActorPunningSubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestActorPunningChild : public PTestActorPunningChild { + friend class PTestActorPunningChild; + + public: + TestActorPunningChild() {} + virtual ~TestActorPunningChild() {} + + protected: + PTestActorPunningPunnedChild* AllocPTestActorPunningPunnedChild(); + bool DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild* a); + + PTestActorPunningSubChild* AllocPTestActorPunningSubChild(); + bool DeallocPTestActorPunningSubChild(PTestActorPunningSubChild* a); + + mozilla::ipc::IPCResult RecvStart(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + fail("should have been killed off!"); + } +}; + +class TestActorPunningPunnedChild : public PTestActorPunningPunnedChild { + public: + TestActorPunningPunnedChild() {} + virtual ~TestActorPunningPunnedChild() {} +}; + +class TestActorPunningSubChild : public PTestActorPunningSubChild { + public: + TestActorPunningSubChild() {} + virtual ~TestActorPunningSubChild() {} + + mozilla::ipc::IPCResult RecvBad(); +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestActorPunning_h diff --git a/ipc/ipdl/test/cxx/TestAsyncReturns.cpp b/ipc/ipdl/test/cxx/TestAsyncReturns.cpp new file mode 100644 index 0000000000..76597143c0 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestAsyncReturns.cpp @@ -0,0 +1,101 @@ +#include "TestAsyncReturns.h" + +#include "IPDLUnitTests.h" // fail etc. + +#include "mozilla/AbstractThread.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace _ipdltest { + +static uint32_t sMagic1 = 0x105b59fb; +static uint32_t sMagic2 = 0x09b6f5e3; + +//----------------------------------------------------------------------------- +// parent + +TestAsyncReturnsParent::TestAsyncReturnsParent() { + MOZ_COUNT_CTOR(TestAsyncReturnsParent); +} + +TestAsyncReturnsParent::~TestAsyncReturnsParent() { + MOZ_COUNT_DTOR(TestAsyncReturnsParent); +} + +void TestAsyncReturnsParent::Main() { + SendNoReturn()->Then( + MessageLoop::current()->SerialEventTarget(), __func__, + [](bool unused) { fail("resolve handler should not be called"); }, + [](ResponseRejectReason&& aReason) { + // MozPromise asserts in debug build if the + // handler is not called + if (aReason != ResponseRejectReason::ChannelClosed) { + fail("reject with wrong reason"); + } + passed("reject handler called on channel close"); + }); + SendPing()->Then( + MessageLoop::current()->SerialEventTarget(), __func__, + [this](bool one) { + if (one) { + passed("take one argument"); + } else { + fail("get one argument but has wrong value"); + } + + // Also try with the callback-based API. + SendPing( + [this](bool one) { + if (one) { + passed("take one argument"); + } else { + fail("get one argument but has wrong value"); + } + Close(); + }, + [](ResponseRejectReason&& aReason) { fail("sending Ping"); }); + }, + [](ResponseRejectReason&& aReason) { fail("sending Ping"); }); +} + +mozilla::ipc::IPCResult TestAsyncReturnsParent::RecvPong( + PongResolver&& aResolve) { + aResolve(std::tuple<const uint32_t&, const uint32_t&>(sMagic1, sMagic2)); + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestAsyncReturnsChild::TestAsyncReturnsChild() { + MOZ_COUNT_CTOR(TestAsyncReturnsChild); +} + +TestAsyncReturnsChild::~TestAsyncReturnsChild() { + MOZ_COUNT_DTOR(TestAsyncReturnsChild); +} + +mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvNoReturn( + NoReturnResolver&& aResolve) { + // Not resolving the promise intentionally + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvPing( + PingResolver&& aResolve) { + SendPong()->Then( + MessageLoop::current()->SerialEventTarget(), __func__, + [aResolve](const std::tuple<uint32_t, uint32_t>& aParam) { + if (std::get<0>(aParam) == sMagic1 && std::get<1>(aParam) == sMagic2) { + passed("take two arguments"); + } else { + fail("get two argument but has wrong value"); + } + aResolve(true); + }, + [](ResponseRejectReason&& aReason) { fail("sending Pong"); }); + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestAsyncReturns.h b/ipc/ipdl/test/cxx/TestAsyncReturns.h new file mode 100644 index 0000000000..5dad3da0ab --- /dev/null +++ b/ipc/ipdl/test/cxx/TestAsyncReturns.h @@ -0,0 +1,54 @@ +#ifndef mozilla__ipdltest_TestAsyncReturns_h +#define mozilla__ipdltest_TestAsyncReturns_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestAsyncReturnsParent.h" +#include "mozilla/_ipdltest/PTestAsyncReturnsChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestAsyncReturnsParent : public PTestAsyncReturnsParent { + friend class PTestAsyncReturnsParent; + + public: + TestAsyncReturnsParent(); + virtual ~TestAsyncReturnsParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvPong(PongResolver&& aResolve); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestAsyncReturnsChild : public PTestAsyncReturnsChild { + friend class PTestAsyncReturnsChild; + + public: + TestAsyncReturnsChild(); + virtual ~TestAsyncReturnsChild(); + + protected: + mozilla::ipc::IPCResult RecvPing(PingResolver&& aResolve); + mozilla::ipc::IPCResult RecvNoReturn(NoReturnResolver&& aResolve); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestAsyncReturns_h diff --git a/ipc/ipdl/test/cxx/TestBadActor.cpp b/ipc/ipdl/test/cxx/TestBadActor.cpp new file mode 100644 index 0000000000..6c6991dbb2 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestBadActor.cpp @@ -0,0 +1,59 @@ +#include "TestBadActor.h" +#include "IPDLUnitTests.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace _ipdltest { + +void TestBadActorParent::Main() { + // This test is designed to test a race condition where the child sends us + // a message on an actor that we've already destroyed. The child process + // should die, and the parent process should not abort. + + PTestBadActorSubParent* child = SendPTestBadActorSubConstructor(); + if (!child) fail("Sending constructor"); + + Unused << child->Call__delete__(child); +} + +// By default, fatal errors kill the parent process, but this makes it +// hard to test, so instead we use the previous behavior and kill the +// child process. +void TestBadActorParent::HandleFatalError(const char* aErrorMsg) { + if (!!strcmp(aErrorMsg, "incoming message racing with actor deletion")) { + fail("wrong fatal error"); + } + + ipc::ScopedProcessHandle otherProcessHandle; + if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) { + fail("couldn't open child process"); + } else { + if (!base::KillProcess(otherProcessHandle, 0, false)) { + fail("terminating child process"); + } + } +} + +PTestBadActorSubParent* TestBadActorParent::AllocPTestBadActorSubParent() { + return new TestBadActorSubParent(); +} + +mozilla::ipc::IPCResult TestBadActorSubParent::RecvPing() { + fail("Shouldn't have received ping."); + return IPC_FAIL_NO_REASON(this); +} + +PTestBadActorSubChild* TestBadActorChild::AllocPTestBadActorSubChild() { + return new TestBadActorSubChild(); +} + +mozilla::ipc::IPCResult TestBadActorChild::RecvPTestBadActorSubConstructor( + PTestBadActorSubChild* actor) { + if (!actor->SendPing()) { + fail("Couldn't send ping to an actor which supposedly isn't dead yet."); + } + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestBadActor.h b/ipc/ipdl/test/cxx/TestBadActor.h new file mode 100644 index 0000000000..cefe0288f4 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestBadActor.h @@ -0,0 +1,84 @@ +#ifndef mozilla__ipdltest_TestBadActor_h +#define mozilla__ipdltest_TestBadActor_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestBadActorParent.h" +#include "mozilla/_ipdltest/PTestBadActorChild.h" + +#include "mozilla/_ipdltest/PTestBadActorSubParent.h" +#include "mozilla/_ipdltest/PTestBadActorSubChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestBadActorParent : public PTestBadActorParent { + friend class PTestBadActorParent; + + public: + TestBadActorParent() {} + virtual ~TestBadActorParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction"); + passed("ok"); + QuitParent(); + } + + virtual void HandleFatalError(const char* aErrorMsg) override; + + PTestBadActorSubParent* AllocPTestBadActorSubParent(); + + bool DeallocPTestBadActorSubParent(PTestBadActorSubParent* actor) { + delete actor; + return true; + } +}; + +class TestBadActorSubParent : public PTestBadActorSubParent { + friend class PTestBadActorSubParent; + + public: + TestBadActorSubParent() {} + virtual ~TestBadActorSubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} + mozilla::ipc::IPCResult RecvPing(); +}; + +class TestBadActorChild : public PTestBadActorChild { + friend class PTestBadActorChild; + + public: + TestBadActorChild() {} + virtual ~TestBadActorChild() {} + + protected: + virtual PTestBadActorSubChild* AllocPTestBadActorSubChild(); + + virtual bool DeallocPTestBadActorSubChild(PTestBadActorSubChild* actor) { + delete actor; + return true; + } + + virtual mozilla::ipc::IPCResult RecvPTestBadActorSubConstructor( + PTestBadActorSubChild* actor); +}; + +class TestBadActorSubChild : public PTestBadActorSubChild { + public: + TestBadActorSubChild() {} + virtual ~TestBadActorSubChild() {} +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // mozilla__ipdltest_TestBadActor_h diff --git a/ipc/ipdl/test/cxx/TestCancel.cpp b/ipc/ipdl/test/cxx/TestCancel.cpp new file mode 100644 index 0000000000..2f97aa2e93 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestCancel.cpp @@ -0,0 +1,115 @@ +#include "TestCancel.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestCancelParent::TestCancelParent() { MOZ_COUNT_CTOR(TestCancelParent); } + +TestCancelParent::~TestCancelParent() { MOZ_COUNT_DTOR(TestCancelParent); } + +void TestCancelParent::Main() { + if (SendTest1_1()) fail("sending Test1_1"); + + uint32_t value = 0; + if (!SendCheckChild(&value)) fail("Test1 CheckChild"); + + if (value != 12) fail("Test1 CheckChild reply"); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvDone1() { + if (!SendStart2()) fail("sending Start2"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvTest2_1() { + if (SendTest2_2()) fail("sending Test2_2"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvStart3() { + if (SendTest3_1()) fail("sending Test3_1"); + + uint32_t value = 0; + if (!SendCheckChild(&value)) fail("Test1 CheckChild"); + + if (value != 12) fail("Test1 CheckChild reply"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvTest3_2() { + GetIPCChannel()->CancelCurrentTransaction(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvDone() { + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "ipc::IToplevelProtocol::Close", this, &TestCancelParent::Close)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelParent::RecvCheckParent(uint32_t* reply) { + *reply = 12; + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +mozilla::ipc::IPCResult TestCancelChild::RecvTest1_1() { + GetIPCChannel()->CancelCurrentTransaction(); + + uint32_t value = 0; + if (!SendCheckParent(&value)) fail("Test1 CheckParent"); + + if (value != 12) fail("Test1 CheckParent reply"); + + if (!SendDone1()) fail("Test1 CheckParent"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelChild::RecvStart2() { + if (!SendTest2_1()) fail("sending Test2_1"); + + if (!SendStart3()) fail("sending Start3"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelChild::RecvTest2_2() { + GetIPCChannel()->CancelCurrentTransaction(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelChild::RecvTest3_1() { + if (SendTest3_2()) fail("sending Test3_2"); + + uint32_t value = 0; + if (!SendCheckParent(&value)) fail("Test1 CheckParent"); + + if (value != 12) fail("Test1 CheckParent reply"); + + if (!SendDone()) fail("sending Done"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestCancelChild::RecvCheckChild(uint32_t* reply) { + *reply = 12; + return IPC_OK(); +} + +TestCancelChild::TestCancelChild() { MOZ_COUNT_CTOR(TestCancelChild); } + +TestCancelChild::~TestCancelChild() { MOZ_COUNT_DTOR(TestCancelChild); } + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestCancel.h b/ipc/ipdl/test/cxx/TestCancel.h new file mode 100644 index 0000000000..7d944d6a69 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestCancel.h @@ -0,0 +1,54 @@ +#ifndef mozilla__ipdltest_TestCancel_h +#define mozilla__ipdltest_TestCancel_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestCancelParent.h" +#include "mozilla/_ipdltest/PTestCancelChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestCancelParent : public PTestCancelParent { + public: + TestCancelParent(); + virtual ~TestCancelParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + mozilla::ipc::IPCResult RecvDone1(); + mozilla::ipc::IPCResult RecvTest2_1(); + mozilla::ipc::IPCResult RecvStart3(); + mozilla::ipc::IPCResult RecvTest3_2(); + mozilla::ipc::IPCResult RecvDone(); + + mozilla::ipc::IPCResult RecvCheckParent(uint32_t* reply); + + virtual void ActorDestroy(ActorDestroyReason why) override { + passed("ok"); + QuitParent(); + } +}; + +class TestCancelChild : public PTestCancelChild { + public: + TestCancelChild(); + virtual ~TestCancelChild(); + + mozilla::ipc::IPCResult RecvTest1_1(); + mozilla::ipc::IPCResult RecvStart2(); + mozilla::ipc::IPCResult RecvTest2_2(); + mozilla::ipc::IPCResult RecvTest3_1(); + + mozilla::ipc::IPCResult RecvCheckChild(uint32_t* reply); + + virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestCancel_h diff --git a/ipc/ipdl/test/cxx/TestCrashCleanup.cpp b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp new file mode 100644 index 0000000000..6a19cc0f65 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp @@ -0,0 +1,100 @@ +#include "TestCrashCleanup.h" + +#include "base/task.h" +#include "mozilla/CondVar.h" +#include "mozilla/Mutex.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +using mozilla::CondVar; +using mozilla::Mutex; +using mozilla::MutexAutoLock; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +namespace { + +// NB: this test does its own shutdown, rather than going through +// QuitParent(), because it's testing degenerate edge cases + +void DeleteSubprocess(Mutex* mutex, CondVar* cvar) { + MutexAutoLock lock(*mutex); + + gSubprocess->Destroy(); + gSubprocess = nullptr; + + cvar->Notify(); +} + +void DeleteTheWorld() { + delete static_cast<TestCrashCleanupParent*>(gParentActor); + gParentActor = nullptr; + + // needs to be synchronous to avoid affecting event ordering on + // the main thread + Mutex mutex MOZ_UNANNOTATED("TestCrashCleanup.DeleteTheWorld.mutex"); + CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar"); + + MutexAutoLock lock(mutex); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction("DeleteSubprocess", DeleteSubprocess, &mutex, &cvar)); + + cvar.Wait(); +} + +void Done() { + static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); + appShell->Exit(); + + passed(__FILE__); +} + +} // namespace + +TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false) { + MOZ_COUNT_CTOR(TestCrashCleanupParent); +} + +TestCrashCleanupParent::~TestCrashCleanupParent() { + MOZ_COUNT_DTOR(TestCrashCleanupParent); + + if (!mCleanedUp) fail("should have been ActorDestroy()d!"); +} + +void TestCrashCleanupParent::Main() { + // NB: has to be enqueued before IO thread's error notification + MessageLoop::current()->PostTask( + NewRunnableFunction("DeleteTheWorld", DeleteTheWorld)); + + if (CallDIEDIEDIE()) fail("expected an error!"); + + Close(); + + MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done)); +} + +//----------------------------------------------------------------------------- +// child + +TestCrashCleanupChild::TestCrashCleanupChild() { + MOZ_COUNT_CTOR(TestCrashCleanupChild); +} + +TestCrashCleanupChild::~TestCrashCleanupChild() { + MOZ_COUNT_DTOR(TestCrashCleanupChild); +} + +mozilla::ipc::IPCResult TestCrashCleanupChild::AnswerDIEDIEDIE() { + _exit(0); + MOZ_CRASH("unreached"); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestCrashCleanup.h b/ipc/ipdl/test/cxx/TestCrashCleanup.h new file mode 100644 index 0000000000..30371264e6 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestCrashCleanup.h @@ -0,0 +1,49 @@ +#ifndef mozilla__ipdltest_TestCrashCleanup_h +#define mozilla__ipdltest_TestCrashCleanup_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestCrashCleanupParent.h" +#include "mozilla/_ipdltest/PTestCrashCleanupChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestCrashCleanupParent : public PTestCrashCleanupParent { + public: + TestCrashCleanupParent(); + virtual ~TestCrashCleanupParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + mCleanedUp = true; + } + + bool mCleanedUp; +}; + +class TestCrashCleanupChild : public PTestCrashCleanupChild { + friend class PTestCrashCleanupChild; + + public: + TestCrashCleanupChild(); + virtual ~TestCrashCleanupChild(); + + protected: + mozilla::ipc::IPCResult AnswerDIEDIEDIE(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + fail("should have 'crashed'!"); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestCrashCleanup_h diff --git a/ipc/ipdl/test/cxx/TestDataStructures.cpp b/ipc/ipdl/test/cxx/TestDataStructures.cpp new file mode 100644 index 0000000000..5b1cabfe7d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDataStructures.cpp @@ -0,0 +1,888 @@ +#include "TestDataStructures.h" + +#include "mozilla/Unused.h" + +#include "IPDLUnitTests.h" // fail etc. + +typedef nsTArray<nsIntRegion> RegionArray; + +namespace mozilla { +namespace _ipdltest { + +static const uint32_t nactors = 10; + +#define test_assert(_cond, _msg) \ + if (!(_cond)) fail(_msg) + +template <typename T> +static void assert_arrays_equal(const nsTArray<T>& a, const nsTArray<T>& b) { + test_assert(a == b, "arrays equal"); +} + +inline static TestDataStructuresSub& Cast(PTestDataStructuresSubParent* a) { + return *static_cast<TestDataStructuresSub*>(a); +} + +//----------------------------------------------------------------------------- +// parent + +TestDataStructuresParent::TestDataStructuresParent() { + MOZ_COUNT_CTOR(TestDataStructuresParent); +} + +TestDataStructuresParent::~TestDataStructuresParent() { + MOZ_COUNT_DTOR(TestDataStructuresParent); +} + +void TestDataStructuresParent::Main() { + for (uint32_t i = 0; i < nactors; ++i) + if (!SendPTestDataStructuresSubConstructor(i)) fail("can't alloc actor"); + + if (!SendStart()) fail("can't send Start()"); +} + +bool TestDataStructuresParent::DeallocPTestDataStructuresSubParent( + PTestDataStructuresSubParent* actor) { + test_assert(Cast(actor).mI == Cast(mKids[0]).mI, "dtor sent to wrong actor"); + mKids.RemoveElementAt(0); + delete actor; + if (mKids.Length() > 0) return true; + + return true; +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest1(nsTArray<int>&& ia, + nsTArray<int>* oa) { + test_assert(5 == ia.Length(), "wrong length"); + for (int i = 0; i < 5; ++i) test_assert(i == ia[i], "wrong value"); + + *oa = ia; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest2( + nsTArray<PTestDataStructuresSubParent*>&& i1, + nsTArray<PTestDataStructuresSubParent*>* o1) { + test_assert(nactors == i1.Length(), "wrong #actors"); + for (uint32_t i = 0; i < i1.Length(); ++i) + test_assert(i == Cast(i1[i]).mI, "wrong mI value"); + *o1 = i1; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest3(const IntDouble& i1, + const IntDouble& i2, + IntDouble* o1, + IntDouble* o2) { + test_assert(42 == i1.get_int(), "wrong value"); + test_assert(4.0 == i2.get_double(), "wrong value"); + + *o1 = i1; + *o2 = i2; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest4( + nsTArray<IntDouble>&& i1, nsTArray<IntDouble>* o1) { + test_assert(4 == i1.Length(), "wrong length"); + test_assert(1 == i1[0].get_int(), "wrong value"); + test_assert(2.0 == i1[1].get_double(), "wrong value"); + test_assert(3 == i1[2].get_int(), "wrong value"); + test_assert(4.0 == i1[3].get_double(), "wrong value"); + + *o1 = i1; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest5( + const IntDoubleArrays& i1, const IntDoubleArrays& i2, + const IntDoubleArrays& i3, IntDoubleArrays* o1, IntDoubleArrays* o2, + IntDoubleArrays* o3) { + test_assert(42 == i1.get_int(), "wrong value"); + + const nsTArray<int>& i2a = i2.get_ArrayOfint(); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + const nsTArray<double>& i3a = i3.get_ArrayOfdouble(); + test_assert(3 == i3a.Length(), "wrong length"); + test_assert(1.0 == i3a[0], "wrong value"); + test_assert(2.0 == i3a[1], "wrong value"); + test_assert(3.0 == i3a[2], "wrong value"); + + *o1 = i1; + *o2 = i2a; + *o3 = i3a; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest7_0( + const ActorWrapper& i1, ActorWrapper* o1) { + if (i1.actorChild() != nullptr) + fail("child side actor should always be null"); + + if (i1.actorParent() != mKids[0]) + fail("should have got back same actor on parent side"); + + o1->actorParent() = mKids[0]; + // malicious behavior + o1->actorChild() = + reinterpret_cast<PTestDataStructuresSubChild*>(uintptr_t(0xdeadbeef)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest6( + nsTArray<IntDoubleArrays>&& i1, nsTArray<IntDoubleArrays>* o1) { + test_assert(3 == i1.Length(), "wrong length"); + + IntDoubleArrays id1(i1[0]); + test_assert(42 == id1.get_int(), "wrong value"); + + nsTArray<int> i2a(i1[1].get_ArrayOfint()); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + nsTArray<double> i3a(i1[2].get_ArrayOfdouble()); + test_assert(3 == i3a.Length(), "wrong length"); + test_assert(1.0 == i3a[0], "wrong value"); + test_assert(2.0 == i3a[1], "wrong value"); + test_assert(3.0 == i3a[2], "wrong value"); + + o1->AppendElement(id1); + o1->AppendElement(IntDoubleArrays(i2a)); + o1->AppendElement(IntDoubleArrays(i3a)); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest7( + const Actors& i1, const Actors& i2, const Actors& i3, Actors* o1, + Actors* o2, Actors* o3) { + test_assert(42 == i1.get_int(), "wrong value"); + + nsTArray<int> i2a(i2.get_ArrayOfint()); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent()); + + *o1 = 42; + *o2 = i2a; + *o3 = mKids; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest8( + nsTArray<Actors>&& i1, nsTArray<Actors>* o1) { + test_assert(3 == i1.Length(), "wrong length"); + test_assert(42 == i1[0].get_int(), "wrong value"); + + const nsTArray<int>& i2a = i1[1].get_ArrayOfint(); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent()); + + *o1 = i1; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest9( + const Unions& i1, const Unions& i2, const Unions& i3, const Unions& i4, + Unions* o1, Unions* o2, Unions* o3, Unions* o4) { + test_assert(42 == i1.get_int(), "wrong value"); + + const nsTArray<int>& i2a = i2.get_ArrayOfint(); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent()); + + const nsTArray<PTestDataStructuresSubParent*>& i4a = + i4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent(); + assert_arrays_equal(mKids, i4a); + + *o1 = i1; + *o2 = i2; + *o3 = i3; + *o4 = i4; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest10( + nsTArray<Unions>&& i1, nsTArray<Unions>* o1) { + test_assert(42 == i1[0].get_int(), "wrong value"); + + const nsTArray<int>& i2a = i1[1].get_ArrayOfint(); + test_assert(3 == i2a.Length(), "wrong length"); + test_assert(1 == i2a[0], "wrong value"); + test_assert(2 == i2a[1], "wrong value"); + test_assert(3 == i2a[2], "wrong value"); + + assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent()); + + const nsTArray<PTestDataStructuresSubParent*>& i4a = + i1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent(); + assert_arrays_equal(mKids, i4a); + + *o1 = i1; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest11( + const SIntDouble& i, SIntDouble* o) { + test_assert(1 == i.i(), "wrong value"); + test_assert(2.0 == i.d(), "wrong value"); + *o = i; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest12( + const SIntDoubleArrays& i, SIntDoubleArrays* o) { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + nsTArray<double> ad; + ad.AppendElement(.5); + ad.AppendElement(1.0); + ad.AppendElement(2.0); + + test_assert(42 == i.i(), "wrong value"); + assert_arrays_equal(ai, i.ai()); + assert_arrays_equal(ad, i.ad()); + + *o = i; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest13(const SActors& i, + SActors* o) { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + test_assert(42 == i.i(), "wrong value"); + assert_arrays_equal(ai, i.ai()); + assert_arrays_equal(mKids, i.apParent()); + + *o = i; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest14(const Structs& i, + Structs* o) { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + test_assert(42 == i.i(), "wrong value"); + assert_arrays_equal(ai, i.ai()); + assert_arrays_equal(mKids, i.apParent()); + + const SActors& ia = i.aa()[0]; + test_assert(42 == ia.i(), "wrong value"); + assert_arrays_equal(ai, ia.ai()); + assert_arrays_equal(mKids, ia.apParent()); + + *o = i; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest15( + const WithStructs& i1, const WithStructs& i2, const WithStructs& i3, + const WithStructs& i4, const WithStructs& i5, WithStructs* o1, + WithStructs* o2, WithStructs* o3, WithStructs* o4, WithStructs* o5) { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + test_assert(i1 == int(42), "wrong value"); + assert_arrays_equal(i2.get_ArrayOfint(), ai); + assert_arrays_equal(i3.get_ArrayOfPTestDataStructuresSubParent(), mKids); + + const SActors& ia = i4.get_ArrayOfSActors()[0]; + test_assert(42 == ia.i(), "wrong value"); + assert_arrays_equal(ai, ia.ai()); + assert_arrays_equal(mKids, ia.apParent()); + + const Structs& is = i5.get_ArrayOfStructs()[0]; + test_assert(42 == is.i(), "wrong value"); + assert_arrays_equal(ai, is.ai()); + assert_arrays_equal(mKids, is.apParent()); + + const SActors& isa = is.aa()[0]; + test_assert(42 == isa.i(), "wrong value"); + assert_arrays_equal(ai, isa.ai()); + assert_arrays_equal(mKids, isa.apParent()); + + *o1 = i1; + *o2 = i2; + *o3 = i3; + *o4 = i4; + *o5 = i5; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest16( + const WithUnions& i, WithUnions* o) { + test_assert(i.i() == 42, "wrong value"); + + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + assert_arrays_equal(ai, i.ai()); + + assert_arrays_equal(i.apParent(), mKids); + + assert_arrays_equal(mKids, + i.aa()[0].get_ArrayOfPTestDataStructuresSubParent()); + + const nsTArray<Unions>& iau = i.au(); + test_assert(iau[0] == 42, "wrong value"); + assert_arrays_equal(ai, iau[1].get_ArrayOfint()); + assert_arrays_equal(mKids, iau[2].get_ArrayOfPTestDataStructuresSubParent()); + assert_arrays_equal( + mKids, + iau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent()); + + *o = i; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest17( + nsTArray<Op>&& sa) { + test_assert(sa.Length() == 1 && Op::TSetAttrs == sa[0].type(), "wrong value"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest18(RegionArray&& ra) { + for (RegionArray::index_type i = 0; i < ra.Length(); ++i) { + // if |ra| has been realloc()d and given a different allocator + // chunk, this loop will nondeterministically crash or iloop. + for (auto iter = ra[i].RectIter(); !iter.Done(); iter.Next()) { + Unused << iter.Get(); + } + } + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestDataStructuresChild::TestDataStructuresChild() { + MOZ_COUNT_CTOR(TestDataStructuresChild); +} + +TestDataStructuresChild::~TestDataStructuresChild() { + MOZ_COUNT_DTOR(TestDataStructuresChild); +} + +mozilla::ipc::IPCResult TestDataStructuresChild::RecvStart() { + puts("[TestDataStructuresChild] starting"); + + Test1(); + Test2(); + Test3(); + Test4(); + Test5(); + Test6(); + Test7_0(); + Test7(); + Test8(); + Test9(); + Test10(); + Test11(); + Test12(); + Test13(); + Test14(); + Test15(); + Test16(); + Test17(); + if (OtherPid() != base::GetCurrentProcId()) { + // FIXME/bug 703317 allocation of nsIntRegion uses a global + // region pool which breaks threads + Test18(); + } + + for (uint32_t i = 0; i < nactors; ++i) + if (!PTestDataStructuresSubChild::Send__delete__(mKids[i])) + fail("can't send dtor"); + + Close(); + + return IPC_OK(); +} + +void TestDataStructuresChild::Test1() { + nsTArray<int> ia; + + for (int i = 0; i < 5; ++i) ia.AppendElement(i); + + nsTArray<int> oa; + if (!SendTest1(ia, &oa)) fail("can't send Test1"); + + assert_arrays_equal(ia, oa); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test2() { + nsTArray<PTestDataStructuresSubChild*> oa; + if (!SendTest2(mKids, &oa)) fail("can't send Test2"); + assert_arrays_equal(mKids, oa); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test3() { + int i1i = 42; + double i2d = 4.0; + IntDouble i1(i1i); + IntDouble i2(i2d); + IntDouble o1, o2; + + SendTest3(i1, i2, &o1, &o2); + + test_assert(i1i == o1.get_int(), "wrong value"); + test_assert(i2d == o2.get_double(), "wrong value"); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test4() { + nsTArray<IntDouble> i1; + i1.AppendElement(IntDouble(int(1))); + i1.AppendElement(IntDouble(2.0)); + i1.AppendElement(IntDouble(int(3))); + i1.AppendElement(IntDouble(4.0)); + + nsTArray<IntDouble> o1; + if (!SendTest4(i1, &o1)) fail("can't send Test4"); + + // TODO Union::operator==() + test_assert(i1.Length() == o1.Length(), "wrong length"); + test_assert(1 == o1[0].get_int(), "wrong value"); + test_assert(2.0 == o1[1].get_double(), "wrong value"); + test_assert(3 == o1[2].get_int(), "wrong value"); + test_assert(4.0 == o1[3].get_double(), "wrong value"); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test5() { + IntDoubleArrays i1(int(42)); + nsTArray<int> i2; + i2.AppendElement(1); + i2.AppendElement(2); + i2.AppendElement(3); + nsTArray<double> i3; + i3.AppendElement(1.0); + i3.AppendElement(2.0); + i3.AppendElement(3.0); + + IntDoubleArrays o1, o2, o3; + if (!SendTest5(i1, IntDoubleArrays(i2), IntDoubleArrays(i3), &o1, &o2, &o3)) + fail("can't send Test5"); + + test_assert(42 == o1.get_int(), "wrong value"); + assert_arrays_equal(i2, o2.get_ArrayOfint()); + assert_arrays_equal(i3, o3.get_ArrayOfdouble()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test6() { + IntDoubleArrays id1(int(42)); + nsTArray<int> id2; + id2.AppendElement(1); + id2.AppendElement(2); + id2.AppendElement(3); + nsTArray<double> id3; + id3.AppendElement(1.0); + id3.AppendElement(2.0); + id3.AppendElement(3.0); + + nsTArray<IntDoubleArrays> i1; + i1.AppendElement(id1); + i1.AppendElement(IntDoubleArrays(id2)); + i1.AppendElement(IntDoubleArrays(id3)); + + nsTArray<IntDoubleArrays> o1; + if (!SendTest6(i1, &o1)) fail("can't send Test6"); + + test_assert(3 == o1.Length(), "wrong length"); + IntDoubleArrays od1(o1[0]); + nsTArray<int> od2(o1[1].get_ArrayOfint()); + nsTArray<double> od3(o1[2].get_ArrayOfdouble()); + + test_assert(42 == od1.get_int(), "wrong value"); + assert_arrays_equal(id2, od2); + assert_arrays_equal(id3, od3); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test7_0() { + ActorWrapper iaw; + if (iaw.actorChild() != nullptr || iaw.actorParent() != nullptr) + fail("actor members should be null initially"); + + iaw.actorChild() = mKids[0]; + if (iaw.actorParent() != nullptr) + fail("parent should be null on child side after set"); + + ActorWrapper oaw; + if (!SendTest7_0(iaw, &oaw)) fail("sending Test7_0"); + + if (oaw.actorParent() != nullptr) + fail( + "parent accessor on actor-struct members should always be null in " + "child"); + + if (oaw.actorChild() != mKids[0]) + fail("should have got back same child-side actor"); +} + +void TestDataStructuresChild::Test7() { + Actors i1(42); + nsTArray<int> i2a; + i2a.AppendElement(1); + i2a.AppendElement(2); + i2a.AppendElement(3); + + Actors o1, o2, o3; + if (!SendTest7(i1, Actors(i2a), Actors(mKids), &o1, &o2, &o3)) + fail("can't send Test7"); + + test_assert(42 == o1.get_int(), "wrong value"); + assert_arrays_equal(i2a, o2.get_ArrayOfint()); + assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test8() { + Actors i1e(42); + nsTArray<int> i2a; + i2a.AppendElement(1); + i2a.AppendElement(2); + i2a.AppendElement(3); + + nsTArray<Actors> i1; + i1.AppendElement(i1e); + i1.AppendElement(i2a); + i1.AppendElement(mKids); + + nsTArray<Actors> o1; + if (!SendTest8(i1, &o1)) fail("can't send Test8"); + + test_assert(3 == o1.Length(), "wrong length"); + test_assert(42 == o1[0].get_int(), "wrong value"); + assert_arrays_equal(i2a, o1[1].get_ArrayOfint()); + assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test9() { + Unions i1(int(42)); + + nsTArray<int> i2a; + i2a.AppendElement(1); + i2a.AppendElement(2); + i2a.AppendElement(3); + + nsTArray<Actors> i4a; + i4a.AppendElement(mKids); + + Unions o1, o2, o3, o4; + if (!SendTest9(i1, Unions(i2a), Unions(mKids), Unions(i4a), &o1, &o2, &o3, + &o4)) + fail("can't send Test9"); + + test_assert(42 == o1.get_int(), "wrong value"); + assert_arrays_equal(i2a, o2.get_ArrayOfint()); + assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild()); + assert_arrays_equal( + mKids, + o4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test10() { + Unions i1a(int(42)); + + nsTArray<int> i2a; + i2a.AppendElement(1); + i2a.AppendElement(2); + i2a.AppendElement(3); + + nsTArray<Actors> i4a; + i4a.AppendElement(mKids); + + nsTArray<Unions> i1; + i1.AppendElement(i1a); + i1.AppendElement(Unions(i2a)); + i1.AppendElement(Unions(mKids)); + i1.AppendElement(Unions(i4a)); + + nsTArray<Unions> o1; + if (!SendTest10(i1, &o1)) fail("can't send Test10"); + + test_assert(4 == o1.Length(), "wrong length"); + test_assert(42 == o1[0].get_int(), "wrong value"); + assert_arrays_equal(i2a, o1[1].get_ArrayOfint()); + assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild()); + assert_arrays_equal( + mKids, + o1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test11() { + SIntDouble i(1, 2.0); + SIntDouble o; + + if (!SendTest11(i, &o)) fail("sending Test11"); + + test_assert(1 == o.i() && 2.0 == o.d(), "wrong values"); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test12() { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + nsTArray<double> ad; + ad.AppendElement(.5); + ad.AppendElement(1.0); + ad.AppendElement(2.0); + + SIntDoubleArrays i(42, ai, ad); + SIntDoubleArrays o; + + if (!SendTest12(i, &o)) fail("sending Test12"); + + test_assert(42 == o.i(), "wrong value"); + assert_arrays_equal(ai, o.ai()); + assert_arrays_equal(ad, o.ad()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test13() { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + SActors i; + i.i() = 42; + i.ai() = ai; + i.apChild() = mKids; + + SActors o; + if (!SendTest13(i, &o)) fail("can't send Test13"); + + test_assert(42 == o.i(), "wrong value"); + assert_arrays_equal(ai, o.ai()); + assert_arrays_equal(mKids, o.apChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test14() { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + SActors ia; + ia.i() = 42; + ia.ai() = ai; + ia.apChild() = mKids; + nsTArray<SActors> aa; + aa.AppendElement(ia); + + Structs i; + i.i() = 42; + i.ai() = ai; + i.apChild() = mKids; + i.aa() = aa; + + Structs o; + if (!SendTest14(i, &o)) fail("can't send Test14"); + + test_assert(42 == o.i(), "wrong value"); + assert_arrays_equal(ai, o.ai()); + assert_arrays_equal(mKids, o.apChild()); + + const SActors& os = o.aa()[0]; + test_assert(42 == os.i(), "wrong value"); + assert_arrays_equal(ai, os.ai()); + assert_arrays_equal(mKids, os.apChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test15() { + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + + SActors ia; + ia.i() = 42; + ia.ai() = ai; + ia.apChild() = mKids; + nsTArray<SActors> iaa; + iaa.AppendElement(ia); + + Structs is; + is.i() = 42; + is.ai() = ai; + is.apChild() = mKids; + is.aa() = iaa; + nsTArray<Structs> isa; + isa.AppendElement(is); + + WithStructs o1, o2, o3, o4, o5; + if (!SendTest15(WithStructs(42), WithStructs(ai), WithStructs(mKids), + WithStructs(iaa), WithStructs(isa), &o1, &o2, &o3, &o4, &o5)) + fail("sending Test15"); + + test_assert(o1 == int(42), "wrong value"); + assert_arrays_equal(o2.get_ArrayOfint(), ai); + assert_arrays_equal(o3.get_ArrayOfPTestDataStructuresSubChild(), mKids); + + const SActors& oa = o4.get_ArrayOfSActors()[0]; + test_assert(42 == oa.i(), "wrong value"); + assert_arrays_equal(ai, oa.ai()); + assert_arrays_equal(mKids, oa.apChild()); + + const Structs& os = o5.get_ArrayOfStructs()[0]; + test_assert(42 == os.i(), "wrong value"); + assert_arrays_equal(ai, os.ai()); + assert_arrays_equal(mKids, os.apChild()); + + const SActors& osa = os.aa()[0]; + test_assert(42 == osa.i(), "wrong value"); + assert_arrays_equal(ai, osa.ai()); + assert_arrays_equal(mKids, osa.apChild()); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test16() { + WithUnions i; + + i.i() = 42; + + nsTArray<int> ai; + ai.AppendElement(1); + ai.AppendElement(2); + ai.AppendElement(3); + i.ai() = ai; + + i.apChild() = mKids; + + nsTArray<Actors> iaa; + iaa.AppendElement(mKids); + i.aa() = iaa; + + nsTArray<Unions> iau; + iau.AppendElement(int(42)); + iau.AppendElement(ai); + iau.AppendElement(mKids); + iau.AppendElement(iaa); + i.au() = iau; + + WithUnions o; + if (!SendTest16(i, &o)) fail("sending Test16"); + + test_assert(42 == o.i(), "wrong value"); + assert_arrays_equal(o.ai(), ai); + assert_arrays_equal(o.apChild(), mKids); + + const Actors& oaa = o.aa()[0]; + assert_arrays_equal(oaa.get_ArrayOfPTestDataStructuresSubChild(), mKids); + + const nsTArray<Unions>& oau = o.au(); + test_assert(oau[0] == 42, "wrong value"); + assert_arrays_equal(oau[1].get_ArrayOfint(), ai); + assert_arrays_equal(oau[2].get_ArrayOfPTestDataStructuresSubChild(), mKids); + assert_arrays_equal( + oau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild(), + mKids); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test17() { + Attrs attrs; + attrs.common() = CommonAttrs(true); + attrs.specific() = BarAttrs(1.0f); + + nsTArray<Op> ops; + ops.AppendElement(SetAttrs(nullptr, mKids[0], attrs)); + + if (!SendTest17(ops)) fail("sending Test17"); + + printf(" passed %s\n", __FUNCTION__); +} + +void TestDataStructuresChild::Test18() { + const int nelements = 1000; + RegionArray ra; + // big enough to hopefully force a realloc to a different chunk of + // memory on the receiving side, if the workaround isn't working + // correctly. But SetCapacity() here because we don't want to + // crash on the sending side. + ra.SetCapacity(nelements); + for (int i = 0; i < nelements; ++i) { + nsIntRegion r; + r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10)); + ra.AppendElement(r); + } + + if (!SendTest18(ra)) fail("sending Test18"); + + printf(" passed %s\n", __FUNCTION__); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestDataStructures.h b/ipc/ipdl/test/cxx/TestDataStructures.h new file mode 100644 index 0000000000..dc25b5282c --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDataStructures.h @@ -0,0 +1,180 @@ +#ifndef mozilla__ipdltest_TestDataStructures_h +#define mozilla__ipdltest_TestDataStructures_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestDataStructuresParent.h" +#include "mozilla/_ipdltest/PTestDataStructuresChild.h" + +#include "mozilla/_ipdltest/PTestDataStructuresSubParent.h" +#include "mozilla/_ipdltest/PTestDataStructuresSubChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Subprotocol actors + +class TestDataStructuresSub : public PTestDataStructuresSubParent, + public PTestDataStructuresSubChild { + public: + explicit TestDataStructuresSub(uint32_t i) : mI(i) {} + virtual ~TestDataStructuresSub() {} + virtual void ActorDestroy(ActorDestroyReason why) override { + if (Deletion != why) fail("unexpected destruction!"); + } + uint32_t mI; +}; + +//----------------------------------------------------------------------------- +// Main actors + +class TestDataStructuresParent : public PTestDataStructuresParent { + friend class PTestDataStructuresParent; + + public: + TestDataStructuresParent(); + virtual ~TestDataStructuresParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + PTestDataStructuresSubParent* AllocPTestDataStructuresSubParent( + const int& i) { + PTestDataStructuresSubParent* actor = new TestDataStructuresSub(i); + mKids.AppendElement(actor); + return actor; + } + + bool DeallocPTestDataStructuresSubParent(PTestDataStructuresSubParent* actor); + + mozilla::ipc::IPCResult RecvTest1(nsTArray<int>&& i1, nsTArray<int>* o1); + + mozilla::ipc::IPCResult RecvTest2( + nsTArray<PTestDataStructuresSubParent*>&& i1, + nsTArray<PTestDataStructuresSubParent*>* o1); + + mozilla::ipc::IPCResult RecvTest3(const IntDouble& i1, const IntDouble& i2, + IntDouble* o1, IntDouble* o2); + + mozilla::ipc::IPCResult RecvTest4(nsTArray<IntDouble>&& i1, + nsTArray<IntDouble>* o1); + + mozilla::ipc::IPCResult RecvTest5(const IntDoubleArrays& i1, + const IntDoubleArrays& i2, + const IntDoubleArrays& i3, + IntDoubleArrays* o1, IntDoubleArrays* o2, + IntDoubleArrays* o3); + + mozilla::ipc::IPCResult RecvTest6(nsTArray<IntDoubleArrays>&& i1, + nsTArray<IntDoubleArrays>* o1); + + mozilla::ipc::IPCResult RecvTest7_0(const ActorWrapper& i1, ActorWrapper* o1); + + mozilla::ipc::IPCResult RecvTest7(const Actors& i1, const Actors& i2, + const Actors& i3, Actors* o1, Actors* o2, + Actors* o3); + + mozilla::ipc::IPCResult RecvTest8(nsTArray<Actors>&& i1, + nsTArray<Actors>* o1); + + mozilla::ipc::IPCResult RecvTest9(const Unions& i1, const Unions& i2, + const Unions& i3, const Unions& i4, + Unions* o1, Unions* o2, Unions* o3, + Unions* o4); + + mozilla::ipc::IPCResult RecvTest10(nsTArray<Unions>&& i1, + nsTArray<Unions>* o1); + + mozilla::ipc::IPCResult RecvTest11(const SIntDouble& i, SIntDouble* o); + + mozilla::ipc::IPCResult RecvTest12(const SIntDoubleArrays& i, + SIntDoubleArrays* o); + + mozilla::ipc::IPCResult RecvTest13(const SActors& i, SActors* o); + + mozilla::ipc::IPCResult RecvTest14(const Structs& i, Structs* o); + + mozilla::ipc::IPCResult RecvTest15( + const WithStructs& i1, const WithStructs& i2, const WithStructs& i3, + const WithStructs& i4, const WithStructs& i5, WithStructs* o1, + WithStructs* o2, WithStructs* o3, WithStructs* o4, WithStructs* o5); + + mozilla::ipc::IPCResult RecvTest16(const WithUnions& i, WithUnions* o); + + mozilla::ipc::IPCResult RecvTest17(nsTArray<Op>&& sa); + + mozilla::ipc::IPCResult RecvTest18(nsTArray<nsIntRegion>&& ra); + + mozilla::ipc::IPCResult RecvDummy(const ShmemUnion& su, ShmemUnion* rsu) { + *rsu = su; + return IPC_OK(); + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + private: + nsTArray<PTestDataStructuresSubParent*> mKids; +}; + +class TestDataStructuresChild : public PTestDataStructuresChild { + friend class PTestDataStructuresChild; + + public: + TestDataStructuresChild(); + virtual ~TestDataStructuresChild(); + + protected: + PTestDataStructuresSubChild* AllocPTestDataStructuresSubChild(const int& i) { + PTestDataStructuresSubChild* actor = new TestDataStructuresSub(i); + mKids.AppendElement(actor); + return actor; + } + + bool DeallocPTestDataStructuresSubChild(PTestDataStructuresSubChild* actor) { + delete actor; + return true; + } + + mozilla::ipc::IPCResult RecvStart(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + private: + void Test1(); + void Test2(); + void Test3(); + void Test4(); + void Test5(); + void Test6(); + void Test7_0(); + void Test7(); + void Test8(); + void Test9(); + void Test10(); + void Test11(); + void Test12(); + void Test13(); + void Test14(); + void Test15(); + void Test16(); + void Test17(); + void Test18(); + + nsTArray<PTestDataStructuresSubChild*> mKids; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestDataStructures_h diff --git a/ipc/ipdl/test/cxx/TestDemon.cpp b/ipc/ipdl/test/cxx/TestDemon.cpp new file mode 100644 index 0000000000..811f6c3314 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDemon.cpp @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=4 et : + */ +#include "TestDemon.h" + +#include <stdlib.h> + +#include "IPDLUnitTests.h" // fail etc. +#if defined(OS_POSIX) +# include <sys/time.h> +# include <unistd.h> +#else +# include <time.h> +# include <windows.h> +#endif + +namespace mozilla { +namespace _ipdltest { + +const int kMaxStackHeight = 4; + +static LazyLogModule sLogModule("demon"); + +#define DEMON_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__)) + +static int gStackHeight = 0; +static bool gFlushStack = false; + +static int Choose(int count) { +#if defined(OS_POSIX) + return random() % count; +#else + return rand() % count; +#endif +} + +//----------------------------------------------------------------------------- +// parent + +TestDemonParent::TestDemonParent() : mDone(false), mIncoming(), mOutgoing() { + MOZ_COUNT_CTOR(TestDemonParent); +} + +TestDemonParent::~TestDemonParent() { MOZ_COUNT_DTOR(TestDemonParent); } + +void TestDemonParent::Main() { + if (!getenv("MOZ_TEST_IPC_DEMON")) { + QuitParent(); + return; + } +#if defined(OS_POSIX) + srandom(time(nullptr)); +#else + srand(time(nullptr)); +#endif + + DEMON_LOG("Start demon"); + + if (!SendStart()) fail("sending Start"); + + RunUnlimitedSequence(); +} + +#ifdef DEBUG +bool TestDemonParent::ShouldContinueFromReplyTimeout() { + return Choose(2) == 0; +} + +bool TestDemonParent::ArtificialTimeout() { return Choose(5) == 0; } + +void TestDemonParent::ArtificialSleep() { + if (Choose(2) == 0) { + // Sleep for anywhere from 0 to 100 milliseconds. + unsigned micros = Choose(100) * 1000; +# ifdef OS_POSIX + usleep(micros); +# else + Sleep(micros / 1000); +# endif + } +} +#endif + +mozilla::ipc::IPCResult TestDemonParent::RecvAsyncMessage(const int& n) { + DEMON_LOG("Start RecvAsync [%d]", n); + + MOZ_ASSERT(n == mIncoming[0]); + mIncoming[0]++; + + RunLimitedSequence(); + + DEMON_LOG("End RecvAsync [%d]", n); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDemonParent::RecvHiPrioSyncMessage() { + DEMON_LOG("Start RecvHiPrioSyncMessage"); + RunLimitedSequence(); + DEMON_LOG("End RecvHiPrioSyncMessage"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDemonParent::RecvSyncMessage(const int& n) { + DEMON_LOG("Start RecvSync [%d]", n); + + MOZ_ASSERT(n == mIncoming[0]); + mIncoming[0]++; + + RunLimitedSequence(ASYNC_ONLY); + + DEMON_LOG("End RecvSync [%d]", n); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDemonParent::RecvUrgentAsyncMessage(const int& n) { + DEMON_LOG("Start RecvUrgentAsyncMessage [%d]", n); + + MOZ_ASSERT(n == mIncoming[2]); + mIncoming[2]++; + + RunLimitedSequence(ASYNC_ONLY); + + DEMON_LOG("End RecvUrgentAsyncMessage [%d]", n); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDemonParent::RecvUrgentSyncMessage(const int& n) { + DEMON_LOG("Start RecvUrgentSyncMessage [%d]", n); + + MOZ_ASSERT(n == mIncoming[2]); + mIncoming[2]++; + + RunLimitedSequence(ASYNC_ONLY); + + DEMON_LOG("End RecvUrgentSyncMessage [%d]", n); + return IPC_OK(); +} + +void TestDemonParent::RunUnlimitedSequence() { + if (mDone) { + return; + } + + gFlushStack = false; + DoAction(); + + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestDemonParent::RunUnlimitedSequence", this, + &TestDemonParent::RunUnlimitedSequence)); +} + +void TestDemonParent::RunLimitedSequence(int flags) { + if (gStackHeight >= kMaxStackHeight) { + return; + } + gStackHeight++; + + int count = Choose(20); + for (int i = 0; i < count; i++) { + if (!DoAction(flags)) { + gFlushStack = true; + } + if (gFlushStack) { + gStackHeight--; + return; + } + } + + gStackHeight--; +} + +static bool AllowAsync(int outgoing, int incoming) { + return incoming >= outgoing - 5; +} + +bool TestDemonParent::DoAction(int flags) { + if (flags & ASYNC_ONLY) { + if (AllowAsync(mOutgoing[0], mIncoming[0])) { + DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]); + return SendAsyncMessage(mOutgoing[0]++); + } else { + return true; + } + } else { + switch (Choose(3)) { + case 0: + if (AllowAsync(mOutgoing[0], mIncoming[0])) { + DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]); + return SendAsyncMessage(mOutgoing[0]++); + } else { + return true; + } + + case 1: { + DEMON_LOG("Start SendHiPrioSyncMessage"); + bool r = SendHiPrioSyncMessage(); + DEMON_LOG("End SendHiPrioSyncMessage result=%d", r); + return r; + } + + case 2: + DEMON_LOG("Cancel"); + GetIPCChannel()->CancelCurrentTransaction(); + return true; + } + } + MOZ_CRASH(); + return false; +} + +//----------------------------------------------------------------------------- +// child + +TestDemonChild::TestDemonChild() : mIncoming(), mOutgoing() { + MOZ_COUNT_CTOR(TestDemonChild); +} + +TestDemonChild::~TestDemonChild() { MOZ_COUNT_DTOR(TestDemonChild); } + +mozilla::ipc::IPCResult TestDemonChild::RecvStart() { +#ifdef OS_POSIX + srandom(time(nullptr)); +#else + srand(time(nullptr)); +#endif + + DEMON_LOG("RecvStart"); + + RunUnlimitedSequence(); + return IPC_OK(); +} + +#ifdef DEBUG +void TestDemonChild::ArtificialSleep() { + if (Choose(2) == 0) { + // Sleep for anywhere from 0 to 100 milliseconds. + unsigned micros = Choose(100) * 1000; +# ifdef OS_POSIX + usleep(micros); +# else + Sleep(micros / 1000); +# endif + } +} +#endif + +mozilla::ipc::IPCResult TestDemonChild::RecvAsyncMessage(const int& n) { + DEMON_LOG("Start RecvAsyncMessage [%d]", n); + + MOZ_ASSERT(n == mIncoming[0]); + mIncoming[0]++; + + RunLimitedSequence(); + + DEMON_LOG("End RecvAsyncMessage [%d]", n); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestDemonChild::RecvHiPrioSyncMessage() { + DEMON_LOG("Start RecvHiPrioSyncMessage"); + RunLimitedSequence(); + DEMON_LOG("End RecvHiPrioSyncMessage"); + return IPC_OK(); +} + +void TestDemonChild::RunUnlimitedSequence() { + gFlushStack = false; + DoAction(); + + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestDemonChild::RunUnlimitedSequence", this, + &TestDemonChild::RunUnlimitedSequence)); +} + +void TestDemonChild::RunLimitedSequence() { + if (gStackHeight >= kMaxStackHeight) { + return; + } + gStackHeight++; + + int count = Choose(20); + for (int i = 0; i < count; i++) { + if (!DoAction()) { + gFlushStack = true; + } + if (gFlushStack) { + gStackHeight--; + return; + } + } + + gStackHeight--; +} + +bool TestDemonChild::DoAction() { + switch (Choose(6)) { + case 0: + if (AllowAsync(mOutgoing[0], mIncoming[0])) { + DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]); + return SendAsyncMessage(mOutgoing[0]++); + } else { + return true; + } + + case 1: { + DEMON_LOG("Start SendHiPrioSyncMessage"); + bool r = SendHiPrioSyncMessage(); + DEMON_LOG("End SendHiPrioSyncMessage result=%d", r); + return r; + } + + case 2: { + DEMON_LOG("Start SendSyncMessage [%d]", mOutgoing[0]); + bool r = SendSyncMessage(mOutgoing[0]++); + switch (GetIPCChannel()->LastSendError()) { + case SyncSendError::PreviousTimeout: + case SyncSendError::SendingCPOWWhileDispatchingSync: + case SyncSendError::SendingCPOWWhileDispatchingUrgent: + case SyncSendError::NotConnectedBeforeSend: + case SyncSendError::CancelledBeforeSend: + mOutgoing[0]--; + break; + default: + break; + } + DEMON_LOG("End SendSyncMessage result=%d", r); + return r; + } + + case 3: + DEMON_LOG("SendUrgentAsyncMessage [%d]", mOutgoing[2]); + return SendUrgentAsyncMessage(mOutgoing[2]++); + + case 4: { + DEMON_LOG("Start SendUrgentSyncMessage [%d]", mOutgoing[2]); + bool r = SendUrgentSyncMessage(mOutgoing[2]++); + switch (GetIPCChannel()->LastSendError()) { + case SyncSendError::PreviousTimeout: + case SyncSendError::SendingCPOWWhileDispatchingSync: + case SyncSendError::SendingCPOWWhileDispatchingUrgent: + case SyncSendError::NotConnectedBeforeSend: + case SyncSendError::CancelledBeforeSend: + mOutgoing[2]--; + break; + default: + break; + } + DEMON_LOG("End SendUrgentSyncMessage result=%d", r); + return r; + } + + case 5: + DEMON_LOG("Cancel"); + GetIPCChannel()->CancelCurrentTransaction(); + return true; + } + MOZ_CRASH(); + return false; +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestDemon.h b/ipc/ipdl/test/cxx/TestDemon.h new file mode 100644 index 0000000000..ba5b003436 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDemon.h @@ -0,0 +1,91 @@ +#ifndef mozilla__ipdltest_TestDemon_h +#define mozilla__ipdltest_TestDemon_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestDemonParent.h" +#include "mozilla/_ipdltest/PTestDemonChild.h" + +using namespace mozilla::ipc; + +namespace mozilla { +namespace _ipdltest { + +class TestDemonParent : public PTestDemonParent { + public: + TestDemonParent(); + virtual ~TestDemonParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + +#ifdef DEBUG + bool ShouldContinueFromReplyTimeout() override; + bool ArtificialTimeout() override; + + bool NeedArtificialSleep() override { return true; } + void ArtificialSleep() override; +#endif + + mozilla::ipc::IPCResult RecvAsyncMessage(const int& n); + mozilla::ipc::IPCResult RecvHiPrioSyncMessage(); + + mozilla::ipc::IPCResult RecvSyncMessage(const int& n); + mozilla::ipc::IPCResult RecvUrgentAsyncMessage(const int& n); + mozilla::ipc::IPCResult RecvUrgentSyncMessage(const int& n); + + virtual void ActorDestroy(ActorDestroyReason why) override { + mDone = true; + printf("Parent ActorDestroy\n"); + passed("ok"); + QuitParent(); + } + + private: + bool mDone; + int mIncoming[3]; + int mOutgoing[3]; + + enum { + ASYNC_ONLY = 1, + }; + + void RunUnlimitedSequence(); + void RunLimitedSequence(int flags = 0); + bool DoAction(int flags = 0); +}; + +class TestDemonChild : public PTestDemonChild { + public: + TestDemonChild(); + virtual ~TestDemonChild(); + + mozilla::ipc::IPCResult RecvStart(); + +#ifdef DEBUG + bool NeedArtificialSleep() override { return true; } + void ArtificialSleep() override; +#endif + + mozilla::ipc::IPCResult RecvAsyncMessage(const int& n); + mozilla::ipc::IPCResult RecvHiPrioSyncMessage(); + + virtual void ActorDestroy(ActorDestroyReason why) override { _exit(0); } + + virtual void IntentionalCrash() override { _exit(0); } + + private: + int mIncoming[3]; + int mOutgoing[3]; + + void RunUnlimitedSequence(); + void RunLimitedSequence(); + bool DoAction(); +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestDemon_h diff --git a/ipc/ipdl/test/cxx/TestDesc.cpp b/ipc/ipdl/test/cxx/TestDesc.cpp new file mode 100644 index 0000000000..2ae199457d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDesc.cpp @@ -0,0 +1,78 @@ +#include "TestDesc.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent +void TestDescParent::Main() { + PTestDescSubParent* p = CallPTestDescSubConstructor(0); + if (!p) fail("can't allocate Sub"); + + PTestDescSubsubParent* pp = p->CallPTestDescSubsubConstructor(); + if (!pp) fail("can't allocate Subsub"); + + if (!SendTest(pp)) fail("can't send Subsub"); +} + +mozilla::ipc::IPCResult TestDescParent::RecvOk(PTestDescSubsubParent* a) { + if (!a) fail("didn't receive Subsub"); + + if (!PTestDescSubsubParent::Call__delete__(a)) fail("deleting Subsub"); + + Close(); + + return IPC_OK(); +} + +PTestDescSubParent* TestDescParent::AllocPTestDescSubParent( + PTestDescSubsubParent* dummy) { + if (dummy) fail("actor supposed to be null"); + return new TestDescSubParent(); +} +bool TestDescParent::DeallocPTestDescSubParent(PTestDescSubParent* actor) { + delete actor; + return true; +} + +PTestDescSubsubParent* TestDescSubParent::AllocPTestDescSubsubParent() { + return new TestDescSubsubParent(); +} +bool TestDescSubParent::DeallocPTestDescSubsubParent( + PTestDescSubsubParent* actor) { + delete actor; + return true; +} + +//----------------------------------------------------------------------------- +// child + +mozilla::ipc::IPCResult TestDescChild::RecvTest(PTestDescSubsubChild* a) { + if (!a) fail("didn't receive Subsub"); + if (!SendOk(a)) fail("couldn't send Ok()"); + return IPC_OK(); +} + +PTestDescSubChild* TestDescChild::AllocPTestDescSubChild( + PTestDescSubsubChild* dummy) { + if (dummy) fail("actor supposed to be null"); + return new TestDescSubChild(); +} +bool TestDescChild::DeallocPTestDescSubChild(PTestDescSubChild* actor) { + delete actor; + return true; +} + +PTestDescSubsubChild* TestDescSubChild::AllocPTestDescSubsubChild() { + return new TestDescSubsubChild(); +} +bool TestDescSubChild::DeallocPTestDescSubsubChild( + PTestDescSubsubChild* actor) { + delete actor; + return true; +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestDesc.h b/ipc/ipdl/test/cxx/TestDesc.h new file mode 100644 index 0000000000..c9fa04f89c --- /dev/null +++ b/ipc/ipdl/test/cxx/TestDesc.h @@ -0,0 +1,115 @@ +#ifndef mozilla_ipdltest_TestDesc_h +#define mozilla_ipdltest_TestDesc_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestDescParent.h" +#include "mozilla/_ipdltest/PTestDescChild.h" + +#include "mozilla/_ipdltest/PTestDescSubParent.h" +#include "mozilla/_ipdltest/PTestDescSubChild.h" + +#include "mozilla/_ipdltest/PTestDescSubsubParent.h" +#include "mozilla/_ipdltest/PTestDescSubsubChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Top-level +// +class TestDescParent : public PTestDescParent { + friend class PTestDescParent; + + public: + TestDescParent() {} + virtual ~TestDescParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + mozilla::ipc::IPCResult RecvOk(PTestDescSubsubParent* a); + + protected: + PTestDescSubParent* AllocPTestDescSubParent(PTestDescSubsubParent*); + bool DeallocPTestDescSubParent(PTestDescSubParent* actor); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestDescChild : public PTestDescChild { + friend class PTestDescChild; + + public: + TestDescChild() {} + virtual ~TestDescChild() {} + + protected: + PTestDescSubChild* AllocPTestDescSubChild(PTestDescSubsubChild*); + + bool DeallocPTestDescSubChild(PTestDescSubChild* actor); + + mozilla::ipc::IPCResult RecvTest(PTestDescSubsubChild* a); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +//----------------------------------------------------------------------------- +// First descendent +// +class TestDescSubParent : public PTestDescSubParent { + friend class PTestDescSubParent; + + public: + TestDescSubParent() {} + virtual ~TestDescSubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} + PTestDescSubsubParent* AllocPTestDescSubsubParent(); + bool DeallocPTestDescSubsubParent(PTestDescSubsubParent* actor); +}; + +class TestDescSubChild : public PTestDescSubChild { + friend class PTestDescSubChild; + + public: + TestDescSubChild() {} + virtual ~TestDescSubChild() {} + + protected: + PTestDescSubsubChild* AllocPTestDescSubsubChild(); + bool DeallocPTestDescSubsubChild(PTestDescSubsubChild* actor); +}; + +//----------------------------------------------------------------------------- +// Grand-descendent +// +class TestDescSubsubParent : public PTestDescSubsubParent { + public: + TestDescSubsubParent() {} + virtual ~TestDescSubsubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestDescSubsubChild : public PTestDescSubsubChild { + public: + TestDescSubsubChild() {} + virtual ~TestDescSubsubChild() {} +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla_ipdltest_TestDesc_h diff --git a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp new file mode 100644 index 0000000000..4a4366f0ba --- /dev/null +++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +#include "TestEndpointBridgeMain.h" + +#include "base/task.h" +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +using namespace std; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// main process +void TestEndpointBridgeMainParent::Main() { + if (!SendStart()) { + fail("sending Start"); + } +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainParent::RecvBridged( + Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint) { + TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent(); + if (!endpoint.Bind(a)) { + fail("Bind failed"); + } + return IPC_OK(); +} + +void TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + passed("ok"); + QuitParent(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHello() { + if (!SendHi()) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHelloSync() { + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::AnswerHelloRpc() { + if (!CallHiRpc()) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +void TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + + // ActorDestroy() is just a callback from IPDL-generated code, + // which needs the top-level actor (this) to stay alive a little + // longer so other things can be cleaned up. + MessageLoop::current()->PostTask( + do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this))); +} + +//----------------------------------------------------------------------------- +// sub process --- child of main +TestEndpointBridgeMainChild* gEndpointBridgeMainChild; + +TestEndpointBridgeMainChild::TestEndpointBridgeMainChild() + : mSubprocess(nullptr) { + gEndpointBridgeMainChild = this; +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainChild::RecvStart() { + vector<string> subsubArgs; + subsubArgs.push_back("TestEndpointBridgeSub"); + + mSubprocess = new IPDLUnitTestSubprocess(); + if (!mSubprocess->SyncLaunch(subsubArgs)) { + fail("problem launching subprocess"); + } + + IPC::Channel* transport = mSubprocess->GetChannel(); + if (!transport) { + fail("no transport"); + } + + TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent(); + bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle())); + + bsp->Main(); + return IPC_OK(); +} + +void TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + // NB: this is kosher because QuitChild() joins with the IO thread + mSubprocess->Destroy(); + mSubprocess = nullptr; + QuitChild(); +} + +void TestEndpointBridgeSubParent::Main() { + if (!SendPing()) { + fail("sending Ping"); + } +} + +mozilla::ipc::IPCResult TestEndpointBridgeSubParent::RecvBridgeEm() { + Endpoint<PTestEndpointBridgeMainSubParent> parent; + Endpoint<PTestEndpointBridgeMainSubChild> child; + nsresult rv; + rv = PTestEndpointBridgeMainSub::CreateEndpoints( + gEndpointBridgeMainChild->OtherPid(), OtherPid(), &parent, &child); + if (NS_FAILED(rv)) { + fail("opening PTestEndpointOpensOpened"); + } + + if (!gEndpointBridgeMainChild->SendBridged(std::move(parent))) { + fail("SendBridge failed for parent"); + } + if (!SendBridged(std::move(child))) { + fail("SendBridge failed for child"); + } + + return IPC_OK(); +} + +void TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + gEndpointBridgeMainChild->Close(); + + // ActorDestroy() is just a callback from IPDL-generated code, + // which needs the top-level actor (this) to stay alive a little + // longer so other things can be cleaned up. + MessageLoop::current()->PostTask( + do_AddRef(new DeleteTask<TestEndpointBridgeSubParent>(this))); +} + +//----------------------------------------------------------------------------- +// subsub process --- child of sub + +static TestEndpointBridgeSubChild* gBridgeSubChild; + +TestEndpointBridgeSubChild::TestEndpointBridgeSubChild() { + gBridgeSubChild = this; +} + +mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvPing() { + if (!SendBridgeEm()) { + fail("sending BridgeEm"); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvBridged( + Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint) { + TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild(); + + if (!endpoint.Bind(a)) { + fail("failed to Bind"); + } + + if (!a->SendHello()) { + fail("sending Hello"); + } + + return IPC_OK(); +} + +void TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + QuitChild(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::RecvHi() { + if (!SendHelloSync()) { + fail("sending HelloSync"); + } + if (!CallHelloRpc()) { + fail("calling HelloRpc"); + } + if (!mGotHi) { + fail("didn't answer HiRpc"); + } + + // Need to close the channel without message-processing frames on + // the C++ stack + MessageLoop::current()->PostTask( + NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this, + &TestEndpointBridgeMainSubChild::Close)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::AnswerHiRpc() { + mGotHi = true; // d00d + return IPC_OK(); +} + +void TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) { + if (NormalShutdown != why) { + fail("unexpected destruction!"); + } + + gBridgeSubChild->Close(); + + // ActorDestroy() is just a callback from IPDL-generated code, + // which needs the top-level actor (this) to stay alive a little + // longer so other things can be cleaned up. + MessageLoop::current()->PostTask( + do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this))); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h new file mode 100644 index 0000000000..88ac12d71b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +#ifndef mozilla__ipdltest_TestEndpointBridgeMain_h +#define mozilla__ipdltest_TestEndpointBridgeMain_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestEndpointBridgeMainParent.h" +#include "mozilla/_ipdltest/PTestEndpointBridgeMainChild.h" + +#include "mozilla/_ipdltest/PTestEndpointBridgeSubParent.h" +#include "mozilla/_ipdltest/PTestEndpointBridgeSubChild.h" + +#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubParent.h" +#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// "Main" process +// +class TestEndpointBridgeMainParent : public PTestEndpointBridgeMainParent { + friend class PTestEndpointBridgeMainParent; + + public: + TestEndpointBridgeMainParent() {} + virtual ~TestEndpointBridgeMainParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvBridged( + mozilla::ipc::Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +class TestEndpointBridgeMainSubParent + : public PTestEndpointBridgeMainSubParent { + friend class PTestEndpointBridgeMainSubParent; + + public: + explicit TestEndpointBridgeMainSubParent() {} + virtual ~TestEndpointBridgeMainSubParent() {} + + protected: + mozilla::ipc::IPCResult RecvHello(); + mozilla::ipc::IPCResult RecvHelloSync(); + mozilla::ipc::IPCResult AnswerHelloRpc(); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +//----------------------------------------------------------------------------- +// "Sub" process --- child of "main" +// +class TestEndpointBridgeSubParent; + +class TestEndpointBridgeMainChild : public PTestEndpointBridgeMainChild { + friend class PTestEndpointBridgeMainChild; + + public: + TestEndpointBridgeMainChild(); + virtual ~TestEndpointBridgeMainChild() {} + + protected: + mozilla::ipc::IPCResult RecvStart(); + + virtual void ActorDestroy(ActorDestroyReason why) override; + + IPDLUnitTestSubprocess* mSubprocess; +}; + +class TestEndpointBridgeSubParent : public PTestEndpointBridgeSubParent { + friend class PTestEndpointBridgeSubParent; + + public: + TestEndpointBridgeSubParent() {} + virtual ~TestEndpointBridgeSubParent() {} + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvBridgeEm(); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +//----------------------------------------------------------------------------- +// "Subsub" process --- child of "sub" +// +class TestEndpointBridgeSubChild : public PTestEndpointBridgeSubChild { + friend class PTestEndpointBridgeSubChild; + + public: + TestEndpointBridgeSubChild(); + virtual ~TestEndpointBridgeSubChild() {} + + protected: + mozilla::ipc::IPCResult RecvPing(); + + mozilla::ipc::IPCResult RecvBridged( + Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +class TestEndpointBridgeMainSubChild : public PTestEndpointBridgeMainSubChild { + friend class PTestEndpointBridgeMainSubChild; + + public: + explicit TestEndpointBridgeMainSubChild() : mGotHi(false) {} + virtual ~TestEndpointBridgeMainSubChild() {} + + protected: + mozilla::ipc::IPCResult RecvHi(); + mozilla::ipc::IPCResult AnswerHiRpc(); + + virtual void ActorDestroy(ActorDestroyReason why) override; + + bool mGotHi; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestEndpointBridgeMain_h diff --git a/ipc/ipdl/test/cxx/TestEndpointOpens.cpp b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp new file mode 100644 index 0000000000..ca141f7b58 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +#include "base/task.h" +#include "base/thread.h" + +#include "TestEndpointOpens.h" + +#include "IPDLUnitTests.h" // fail etc. + +using namespace mozilla::ipc; + +using base::ProcessHandle; +using base::Thread; + +namespace mozilla { +// NB: this is generally bad style, but I am lazy. +using namespace _ipdltest; +using namespace _ipdltest2; + +static MessageLoop* gMainThread; + +static void AssertNotMainThread() { + if (!gMainThread) { + fail("gMainThread is not initialized"); + } + if (MessageLoop::current() == gMainThread) { + fail("unexpectedly called on the main thread"); + } +} + +//----------------------------------------------------------------------------- +// parent + +// Thread on which TestEndpointOpensOpenedParent runs +static Thread* gParentThread; + +void TestEndpointOpensParent::Main() { + if (!SendStart()) { + fail("sending Start"); + } +} + +static void OpenParent(TestEndpointOpensOpenedParent* aParent, + Endpoint<PTestEndpointOpensOpenedParent>&& aEndpoint) { + AssertNotMainThread(); + + // Open the actor on the off-main thread to park it there. + // Messages will be delivered to this thread's message loop + // instead of the main thread's. + if (!aEndpoint.Bind(aParent)) { + fail("binding Parent"); + } +} + +mozilla::ipc::IPCResult TestEndpointOpensParent::RecvStartSubprotocol( + mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint) { + gMainThread = MessageLoop::current(); + + gParentThread = new Thread("ParentThread"); + if (!gParentThread->Start()) { + fail("starting parent thread"); + } + + TestEndpointOpensOpenedParent* a = new TestEndpointOpensOpenedParent(); + gParentThread->message_loop()->PostTask( + NewRunnableFunction("OpenParent", OpenParent, a, std::move(endpoint))); + + return IPC_OK(); +} + +void TestEndpointOpensParent::ActorDestroy(ActorDestroyReason why) { + // Stops the thread and joins it + delete gParentThread; + + if (NormalShutdown != why) { + fail("unexpected destruction A!"); + } + passed("ok"); + QuitParent(); +} + +mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::RecvHello() { + AssertNotMainThread(); + if (!SendHi()) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::RecvHelloSync() { + AssertNotMainThread(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::AnswerHelloRpc() { + AssertNotMainThread(); + if (!CallHiRpc()) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +static void ShutdownTestEndpointOpensOpenedParent( + TestEndpointOpensOpenedParent* parent, Transport* transport) { + delete parent; +} + +void TestEndpointOpensOpenedParent::ActorDestroy(ActorDestroyReason why) { + AssertNotMainThread(); + + if (NormalShutdown != why) { + fail("unexpected destruction B!"); + } + + // ActorDestroy() is just a callback from IPDL-generated code, + // which needs the top-level actor (this) to stay alive a little + // longer so other things can be cleaned up. + gParentThread->message_loop()->PostTask(NewRunnableFunction( + "ShutdownTestEndpointOpensOpenedParent", + ShutdownTestEndpointOpensOpenedParent, this, GetTransport())); +} + +//----------------------------------------------------------------------------- +// child + +static TestEndpointOpensChild* gOpensChild; +// Thread on which TestEndpointOpensOpenedChild runs +static Thread* gChildThread; + +TestEndpointOpensChild::TestEndpointOpensChild() { gOpensChild = this; } + +static void OpenChild(TestEndpointOpensOpenedChild* aChild, + Endpoint<PTestEndpointOpensOpenedChild>&& endpoint) { + AssertNotMainThread(); + + // Open the actor on the off-main thread to park it there. + // Messages will be delivered to this thread's message loop + // instead of the main thread's. + if (!endpoint.Bind(aChild)) { + fail("binding child endpoint"); + } + + // Kick off the unit tests + if (!aChild->SendHello()) { + fail("sending Hello"); + } +} + +mozilla::ipc::IPCResult TestEndpointOpensChild::RecvStart() { + Endpoint<PTestEndpointOpensOpenedParent> parent; + Endpoint<PTestEndpointOpensOpenedChild> child; + nsresult rv; + rv = PTestEndpointOpensOpened::CreateEndpoints( + OtherPid(), base::GetCurrentProcId(), &parent, &child); + if (NS_FAILED(rv)) { + fail("opening PTestEndpointOpensOpened"); + } + + gMainThread = MessageLoop::current(); + + gChildThread = new Thread("ChildThread"); + if (!gChildThread->Start()) { + fail("starting child thread"); + } + + TestEndpointOpensOpenedChild* a = new TestEndpointOpensOpenedChild(); + gChildThread->message_loop()->PostTask( + NewRunnableFunction("OpenChild", OpenChild, a, std::move(child))); + + if (!SendStartSubprotocol(std::move(parent))) { + fail("send StartSubprotocol"); + } + + return IPC_OK(); +} + +void TestEndpointOpensChild::ActorDestroy(ActorDestroyReason why) { + // Stops the thread and joins it + delete gChildThread; + + if (NormalShutdown != why) { + fail("unexpected destruction C!"); + } + QuitChild(); +} + +mozilla::ipc::IPCResult TestEndpointOpensOpenedChild::RecvHi() { + AssertNotMainThread(); + + if (!SendHelloSync()) { + fail("sending HelloSync"); + } + if (!CallHelloRpc()) { + fail("calling HelloRpc"); + } + if (!mGotHi) { + fail("didn't answer HiRpc"); + } + + // Need to close the channel without message-processing frames on + // the C++ stack + MessageLoop::current()->PostTask( + NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this, + &TestEndpointOpensOpenedChild::Close)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestEndpointOpensOpenedChild::AnswerHiRpc() { + AssertNotMainThread(); + + mGotHi = true; // d00d + return IPC_OK(); +} + +static void ShutdownTestEndpointOpensOpenedChild( + TestEndpointOpensOpenedChild* child, Transport* transport) { + delete child; + + // Kick off main-thread shutdown. + gMainThread->PostTask( + NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", gOpensChild, + &TestEndpointOpensChild::Close)); +} + +void TestEndpointOpensOpenedChild::ActorDestroy(ActorDestroyReason why) { + AssertNotMainThread(); + + if (NormalShutdown != why) { + fail("unexpected destruction D!"); + } + + // ActorDestroy() is just a callback from IPDL-generated code, + // which needs the top-level actor (this) to stay alive a little + // longer so other things can be cleaned up. Defer shutdown to + // let cleanup finish. + gChildThread->message_loop()->PostTask(NewRunnableFunction( + "ShutdownTestEndpointOpensOpenedChild", + ShutdownTestEndpointOpensOpenedChild, this, GetTransport())); +} + +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestEndpointOpens.h b/ipc/ipdl/test/cxx/TestEndpointOpens.h new file mode 100644 index 0000000000..6721274937 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestEndpointOpens.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ + +#ifndef mozilla__ipdltest_TestEndpointOpens_h +#define mozilla__ipdltest_TestEndpointOpens_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestEndpointOpensParent.h" +#include "mozilla/_ipdltest/PTestEndpointOpensChild.h" + +#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedParent.h" +#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedChild.h" + +namespace mozilla { + +// parent process + +namespace _ipdltest { + +class TestEndpointOpensParent : public PTestEndpointOpensParent { + friend class PTestEndpointOpensParent; + + public: + TestEndpointOpensParent() {} + virtual ~TestEndpointOpensParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvStartSubprotocol( + mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +} // namespace _ipdltest + +namespace _ipdltest2 { + +class TestEndpointOpensOpenedParent : public PTestEndpointOpensOpenedParent { + friend class PTestEndpointOpensOpenedParent; + + public: + explicit TestEndpointOpensOpenedParent() {} + virtual ~TestEndpointOpensOpenedParent() {} + + protected: + mozilla::ipc::IPCResult RecvHello(); + mozilla::ipc::IPCResult RecvHelloSync(); + mozilla::ipc::IPCResult AnswerHelloRpc(); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +} // namespace _ipdltest2 + +// child process + +namespace _ipdltest { + +class TestEndpointOpensChild : public PTestEndpointOpensChild { + friend class PTestEndpointOpensChild; + + public: + TestEndpointOpensChild(); + virtual ~TestEndpointOpensChild() {} + + protected: + mozilla::ipc::IPCResult RecvStart(); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +} // namespace _ipdltest + +namespace _ipdltest2 { + +class TestEndpointOpensOpenedChild : public PTestEndpointOpensOpenedChild { + friend class PTestEndpointOpensOpenedChild; + + public: + explicit TestEndpointOpensOpenedChild() : mGotHi(false) {} + virtual ~TestEndpointOpensOpenedChild() {} + + protected: + mozilla::ipc::IPCResult RecvHi(); + mozilla::ipc::IPCResult AnswerHiRpc(); + + virtual void ActorDestroy(ActorDestroyReason why) override; + + bool mGotHi; +}; + +} // namespace _ipdltest2 + +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestEndpointOpens_h diff --git a/ipc/ipdl/test/cxx/TestFailedCtor.cpp b/ipc/ipdl/test/cxx/TestFailedCtor.cpp new file mode 100644 index 0000000000..2f08d2eeb0 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestFailedCtor.cpp @@ -0,0 +1,112 @@ +#include "TestFailedCtor.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent +void TestFailedCtorParent::Main() { + PTestFailedCtorSubParent* p = CallPTestFailedCtorSubConstructor(); + if (p) fail("expected ctor to fail"); + + Close(); +} + +PTestFailedCtorSubParent* +TestFailedCtorParent::AllocPTestFailedCtorSubParent() { + return new TestFailedCtorSubParent(); +} +bool TestFailedCtorParent::DeallocPTestFailedCtorSubParent( + PTestFailedCtorSubParent* actor) { + delete actor; + return true; +} + +PTestFailedCtorSubsubParent* +TestFailedCtorSubParent::AllocPTestFailedCtorSubsubParent() { + TestFailedCtorSubsub* a = new TestFailedCtorSubsub(); + if (!mOne) { + return mOne = a; + } else if (!mTwo) { + return mTwo = a; + } else if (!mThree) { + return mThree = a; + } else { + fail("unexpected Alloc()"); + return nullptr; + } +} +bool TestFailedCtorSubParent::DeallocPTestFailedCtorSubsubParent( + PTestFailedCtorSubsubParent* actor) { + static_cast<TestFailedCtorSubsub*>(actor)->mDealloced = true; + return true; +} + +void TestFailedCtorSubParent::ActorDestroy(ActorDestroyReason why) { + if (mOne->mWhy != Deletion) fail("Subsub one got wrong ActorDestroyReason"); + if (mTwo->mWhy != AncestorDeletion) + fail("Subsub two got wrong ActorDestroyReason"); + if (mThree->mWhy != AncestorDeletion) + fail("Subsub three got wrong ActorDestroyReason"); + + if (FailedConstructor != why) fail("unexpected destruction!"); +} + +TestFailedCtorSubParent::~TestFailedCtorSubParent() { + if (!(mOne->mDealloced && mTwo->mDealloced && mThree->mDealloced)) + fail("Not all subsubs were Dealloc'd"); + delete mOne; + delete mTwo; + delete mThree; +} + +//----------------------------------------------------------------------------- +// child + +PTestFailedCtorSubChild* TestFailedCtorChild::AllocPTestFailedCtorSubChild() { + return new TestFailedCtorSubChild(); +} + +mozilla::ipc::IPCResult +TestFailedCtorChild::AnswerPTestFailedCtorSubConstructor( + PTestFailedCtorSubChild* actor) { + PTestFailedCtorSubsubChild* c1 = + actor->SendPTestFailedCtorSubsubConstructor(); + PTestFailedCtorSubsubChild::Send__delete__(c1); + + if (!actor->SendPTestFailedCtorSubsubConstructor() || + !actor->SendPTestFailedCtorSubsubConstructor() || !actor->SendSync()) + fail("setting up test"); + + // This causes our process to die + return IPC_FAIL_NO_REASON(this); +} + +bool TestFailedCtorChild::DeallocPTestFailedCtorSubChild( + PTestFailedCtorSubChild* actor) { + delete actor; + return true; +} + +void TestFailedCtorChild::ProcessingError(Result aCode, const char* aReason) { + if (OtherPid() != base::GetCurrentProcId()) // thread-mode + _exit(0); +} + +PTestFailedCtorSubsubChild* +TestFailedCtorSubChild::AllocPTestFailedCtorSubsubChild() { + return new TestFailedCtorSubsub(); +} + +bool TestFailedCtorSubChild::DeallocPTestFailedCtorSubsubChild( + PTestFailedCtorSubsubChild* actor) { + delete actor; + return true; +} + +void TestFailedCtorSubChild::ActorDestroy(ActorDestroyReason why) {} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestFailedCtor.h b/ipc/ipdl/test/cxx/TestFailedCtor.h new file mode 100644 index 0000000000..6fac4eb278 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestFailedCtor.h @@ -0,0 +1,127 @@ +#ifndef mozilla_ipdltest_TestFailedCtor_h +#define mozilla_ipdltest_TestFailedCtor_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestFailedCtorParent.h" +#include "mozilla/_ipdltest/PTestFailedCtorChild.h" + +#include "mozilla/_ipdltest/PTestFailedCtorSubParent.h" +#include "mozilla/_ipdltest/PTestFailedCtorSubChild.h" + +#include "mozilla/_ipdltest/PTestFailedCtorSubsubParent.h" +#include "mozilla/_ipdltest/PTestFailedCtorSubsubChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Top-level +// +class TestFailedCtorParent : public PTestFailedCtorParent { + friend class PTestFailedCtorParent; + + public: + TestFailedCtorParent() {} + virtual ~TestFailedCtorParent() {} + + static bool RunTestInProcesses() { return true; } + + // FIXME/bug 703322 Disabled because child calls exit() to end + // test, not clear how to handle failed ctor in + // threaded mode. + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + PTestFailedCtorSubParent* AllocPTestFailedCtorSubParent(); + bool DeallocPTestFailedCtorSubParent(PTestFailedCtorSubParent* actor); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestFailedCtorChild : public PTestFailedCtorChild { + friend class PTestFailedCtorChild; + + public: + TestFailedCtorChild() {} + virtual ~TestFailedCtorChild() {} + + protected: + PTestFailedCtorSubChild* AllocPTestFailedCtorSubChild(); + + mozilla::ipc::IPCResult AnswerPTestFailedCtorSubConstructor( + PTestFailedCtorSubChild* actor) override; + + bool DeallocPTestFailedCtorSubChild(PTestFailedCtorSubChild* actor); + + virtual void ProcessingError(Result aCode, const char* aReason) override; + + virtual void ActorDestroy(ActorDestroyReason why) override { + fail("should have _exit()ed"); + } +}; + +//----------------------------------------------------------------------------- +// First descendent +// +class TestFailedCtorSubsub; + +class TestFailedCtorSubParent : public PTestFailedCtorSubParent { + friend class PTestFailedCtorSubParent; + + public: + TestFailedCtorSubParent() : mOne(nullptr), mTwo(nullptr), mThree(nullptr) {} + virtual ~TestFailedCtorSubParent(); + + protected: + PTestFailedCtorSubsubParent* AllocPTestFailedCtorSubsubParent(); + + bool DeallocPTestFailedCtorSubsubParent(PTestFailedCtorSubsubParent* actor); + mozilla::ipc::IPCResult RecvSync() { return IPC_OK(); } + + virtual void ActorDestroy(ActorDestroyReason why) override; + + TestFailedCtorSubsub* mOne; + TestFailedCtorSubsub* mTwo; + TestFailedCtorSubsub* mThree; +}; + +class TestFailedCtorSubChild : public PTestFailedCtorSubChild { + friend class PTestFailedCtorSubChild; + + public: + TestFailedCtorSubChild() {} + virtual ~TestFailedCtorSubChild() {} + + protected: + PTestFailedCtorSubsubChild* AllocPTestFailedCtorSubsubChild(); + bool DeallocPTestFailedCtorSubsubChild(PTestFailedCtorSubsubChild* actor); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +//----------------------------------------------------------------------------- +// Grand-descendent +// +class TestFailedCtorSubsub : public PTestFailedCtorSubsubParent, + public PTestFailedCtorSubsubChild { + public: + TestFailedCtorSubsub() : mWhy(ActorDestroyReason(-1)), mDealloced(false) {} + virtual ~TestFailedCtorSubsub() {} + + virtual void ActorDestroy(ActorDestroyReason why) override { mWhy = why; } + + ActorDestroyReason mWhy; + bool mDealloced; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla_ipdltest_TestFailedCtor_h diff --git a/ipc/ipdl/test/cxx/TestHangs.cpp b/ipc/ipdl/test/cxx/TestHangs.cpp new file mode 100644 index 0000000000..2694cbfdab --- /dev/null +++ b/ipc/ipdl/test/cxx/TestHangs.cpp @@ -0,0 +1,127 @@ +#include "base/process_util.h" + +#include "TestHangs.h" + +#include "IPDLUnitTests.h" // fail etc. + +using base::KillProcess; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestHangsParent::TestHangsParent() + : mDetectedHang(false), mNumAnswerStackFrame(0) { + MOZ_COUNT_CTOR(TestHangsParent); +} + +TestHangsParent::~TestHangsParent() { MOZ_COUNT_DTOR(TestHangsParent); } + +void TestHangsParent::Main() { + // Here we try to set things up to test the following sequence of events: + // + // - subprocess causes an OnMaybeDequeueOne() task to be posted to + // this thread + // + // - subprocess hangs just long enough for the hang timer to expire + // + // - hang-kill code in the parent starts running + // + // - subprocess replies to message while hang code runs + // + // - reply is processed in OnMaybeDequeueOne() before Close() has + // been called or the channel error notification has been posted + + // this tells the subprocess to send us Nonce() + if (!SendStart()) fail("sending Start"); + + // now we sleep here for a while awaiting the Nonce() message from + // the child. since we're not blocked on anything, the IO thread + // will enqueue an OnMaybeDequeueOne() task to process that + // message + // + // NB: PR_Sleep is exactly what we want, only the current thread + // sleeping + PR_Sleep(5000); + + // when we call into this, we'll pull the Nonce() message out of + // the mPending queue, but that doesn't matter ... the + // OnMaybeDequeueOne() event will remain + if (CallStackFrame() && mDetectedHang) fail("should have timed out!"); + + // the Close() task in the queue will shut us down +} + +bool TestHangsParent::ShouldContinueFromReplyTimeout() { + mDetectedHang = true; + + // so we've detected a timeout after 2 ms ... now we cheat and + // sleep for a long time, to allow the subprocess's reply to come + // in + + PR_Sleep(5000); + + // reply should be here; we'll post a task to shut things down. + // This must be after OnMaybeDequeueOne() in the event queue. + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestHangsParent::CleanUp", this, &TestHangsParent::CleanUp)); + + GetIPCChannel()->CloseWithTimeout(); + + return false; +} + +mozilla::ipc::IPCResult TestHangsParent::AnswerStackFrame() { + ++mNumAnswerStackFrame; + + if (mNumAnswerStackFrame == 1) { + if (CallStackFrame()) { + fail("should have timed out!"); + } + } else if (mNumAnswerStackFrame == 2) { + // minimum possible, 2 ms. We want to detecting a hang to race + // with the reply coming in, as reliably as possible + SetReplyTimeoutMs(2); + + if (CallHang()) fail("should have timed out!"); + } else { + fail("unexpected state"); + } + + return IPC_OK(); +} + +void TestHangsParent::CleanUp() { + ipc::ScopedProcessHandle otherProcessHandle; + if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) { + fail("couldn't open child process"); + } else { + if (!KillProcess(otherProcessHandle, 0, false)) { + fail("terminating child process"); + } + } + Close(); +} + +//----------------------------------------------------------------------------- +// child + +TestHangsChild::TestHangsChild() { MOZ_COUNT_CTOR(TestHangsChild); } + +TestHangsChild::~TestHangsChild() { MOZ_COUNT_DTOR(TestHangsChild); } + +mozilla::ipc::IPCResult TestHangsChild::AnswerHang() { + puts(" (child process is 'hanging' now)"); + + // just sleep until we're reasonably confident the 1ms hang + // detector fired in the parent process and it's sleeping in + // ShouldContinueFromReplyTimeout() + PR_Sleep(1000); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestHangs.h b/ipc/ipdl/test/cxx/TestHangs.h new file mode 100644 index 0000000000..a3dfb991f5 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestHangs.h @@ -0,0 +1,75 @@ +#ifndef mozilla__ipdltest_TestHangs_h +#define mozilla__ipdltest_TestHangs_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestHangsParent.h" +#include "mozilla/_ipdltest/PTestHangsChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestHangsParent : public PTestHangsParent { + friend class PTestHangsParent; + + public: + TestHangsParent(); + virtual ~TestHangsParent(); + + static bool RunTestInProcesses() { return true; } + + // FIXME/bug 703320 Disabled because parent kills child proc, not + // clear how that should work in threads. + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + virtual bool ShouldContinueFromReplyTimeout() override; + + mozilla::ipc::IPCResult RecvNonce() { return IPC_OK(); } + + mozilla::ipc::IPCResult AnswerStackFrame(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + void CleanUp(); + + bool mDetectedHang; + int32_t mNumAnswerStackFrame; +}; + +class TestHangsChild : public PTestHangsChild { + friend class PTestHangsChild; + + public: + TestHangsChild(); + virtual ~TestHangsChild(); + + protected: + mozilla::ipc::IPCResult RecvStart() { + if (!SendNonce()) fail("sending Nonce"); + return IPC_OK(); + } + + mozilla::ipc::IPCResult AnswerStackFrame() { + if (CallStackFrame()) fail("should have failed"); + return IPC_OK(); + } + + mozilla::ipc::IPCResult AnswerHang(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestHangs_h diff --git a/ipc/ipdl/test/cxx/TestHighestPrio.cpp b/ipc/ipdl/test/cxx/TestHighestPrio.cpp new file mode 100644 index 0000000000..e6715fba8e --- /dev/null +++ b/ipc/ipdl/test/cxx/TestHighestPrio.cpp @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=2 ts=4 et : + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestHighestPrio.h" + +#include "IPDLUnitTests.h" // fail etc. +#if defined(OS_POSIX) +# include <unistd.h> +#else +# include <windows.h> +#endif + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestHighestPrioParent::TestHighestPrioParent() : msg_num_(0) { + MOZ_COUNT_CTOR(TestHighestPrioParent); +} + +TestHighestPrioParent::~TestHighestPrioParent() { + MOZ_COUNT_DTOR(TestHighestPrioParent); +} + +void TestHighestPrioParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg1() { + MOZ_ASSERT(msg_num_ == 0); + msg_num_ = 1; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg2() { + MOZ_ASSERT(msg_num_ == 1); + msg_num_ = 2; + + if (!SendStartInner()) fail("sending StartInner"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg3() { + MOZ_ASSERT(msg_num_ == 2); + msg_num_ = 3; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg4() { + MOZ_ASSERT(msg_num_ == 3); + msg_num_ = 4; + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestHighestPrioChild::TestHighestPrioChild() { + MOZ_COUNT_CTOR(TestHighestPrioChild); +} + +TestHighestPrioChild::~TestHighestPrioChild() { + MOZ_COUNT_DTOR(TestHighestPrioChild); +} + +mozilla::ipc::IPCResult TestHighestPrioChild::RecvStart() { + if (!SendMsg1()) fail("sending Msg1"); + + if (!SendMsg2()) fail("sending Msg2"); + + Close(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestHighestPrioChild::RecvStartInner() { + if (!SendMsg3()) fail("sending Msg3"); + + if (!SendMsg4()) fail("sending Msg4"); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestHighestPrio.h b/ipc/ipdl/test/cxx/TestHighestPrio.h new file mode 100644 index 0000000000..34563d7708 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestHighestPrio.h @@ -0,0 +1,55 @@ +#ifndef mozilla__ipdltest_TestHighestPrio_h +#define mozilla__ipdltest_TestHighestPrio_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestHighestPrioParent.h" +#include "mozilla/_ipdltest/PTestHighestPrioChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestHighestPrioParent : public PTestHighestPrioParent { + public: + TestHighestPrioParent(); + virtual ~TestHighestPrioParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + mozilla::ipc::IPCResult RecvMsg1(); + mozilla::ipc::IPCResult RecvMsg2(); + mozilla::ipc::IPCResult RecvMsg3(); + mozilla::ipc::IPCResult RecvMsg4(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + if (msg_num_ != 4) fail("missed IPC call"); + passed("ok"); + QuitParent(); + } + + private: + int msg_num_; +}; + +class TestHighestPrioChild : public PTestHighestPrioChild { + public: + TestHighestPrioChild(); + virtual ~TestHighestPrioChild(); + + mozilla::ipc::IPCResult RecvStart(); + mozilla::ipc::IPCResult RecvStartInner(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestHighestPrio_h diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp new file mode 100644 index 0000000000..3af7ad620d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp @@ -0,0 +1,138 @@ +#include "TestInterruptErrorCleanup.h" + +#include "base/task.h" +#include "mozilla/CondVar.h" +#include "mozilla/Mutex.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +using mozilla::CondVar; +using mozilla::Mutex; +using mozilla::MutexAutoLock; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +namespace { + +// NB: this test does its own shutdown, rather than going through +// QuitParent(), because it's testing degenerate edge cases + +void DeleteSubprocess(Mutex* mutex, CondVar* cvar) { + MutexAutoLock lock(*mutex); + + gSubprocess->Destroy(); + gSubprocess = nullptr; + + cvar->Notify(); +} + +void DeleteTheWorld() { + delete static_cast<TestInterruptErrorCleanupParent*>(gParentActor); + gParentActor = nullptr; + + // needs to be synchronous to avoid affecting event ordering on + // the main thread + Mutex mutex MOZ_UNANNOTATED("TestInterruptErrorCleanup.DeleteTheWorld.mutex"); + CondVar cvar(mutex, "TestInterruptErrorCleanup.DeleteTheWorld.cvar"); + + MutexAutoLock lock(mutex); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction("DeleteSubprocess", DeleteSubprocess, &mutex, &cvar)); + + cvar.Wait(); +} + +void Done() { + static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); + appShell->Exit(); + + passed(__FILE__); +} + +} // namespace + +TestInterruptErrorCleanupParent::TestInterruptErrorCleanupParent() + : mGotProcessingError(false) { + MOZ_COUNT_CTOR(TestInterruptErrorCleanupParent); +} + +TestInterruptErrorCleanupParent::~TestInterruptErrorCleanupParent() { + MOZ_COUNT_DTOR(TestInterruptErrorCleanupParent); +} + +void TestInterruptErrorCleanupParent::Main() { + // This test models the following sequence of events + // + // (1) Parent: Interrupt out-call + // (2) Child: crash + // --[Parent-only hereafter]-- + // (3) Interrupt out-call return false + // (4) Close() + // --[event loop]-- + // (5) delete parentActor + // (6) delete childProcess + // --[event loop]-- + // (7) Channel::OnError notification + // --[event loop]-- + // (8) Done, quit + // + // See bug 535298 and friends; this seqeunce of events captures + // three differnent potential errors + // - Close()-after-error (semantic error previously) + // - use-after-free of parentActor + // - use-after-free of channel + // + // Because of legacy constraints related to nsNPAPI* code, we need + // to ensure that this sequence of events can occur without + // errors/crashes. + + MessageLoop::current()->PostTask( + NewRunnableFunction("DeleteTheWorld", DeleteTheWorld)); + + // it's a failure if this *succeeds* + if (CallError()) fail("expected an error!"); + + if (!mGotProcessingError) fail("expected a ProcessingError() notification"); + + // it's OK to Close() a channel after an error, because nsNPAPI* + // wants to do this + Close(); + + // we know that this event *must* be after the MaybeError + // notification enqueued by AsyncChannel, because that event is + // enqueued within the same mutex that ends up signaling the + // wakeup-on-error of |CallError()| above + MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done)); +} + +void TestInterruptErrorCleanupParent::ProcessingError(Result aCode, + const char* aReason) { + if (aCode != MsgDropped) fail("unexpected processing error"); + mGotProcessingError = true; +} + +//----------------------------------------------------------------------------- +// child + +TestInterruptErrorCleanupChild::TestInterruptErrorCleanupChild() { + MOZ_COUNT_CTOR(TestInterruptErrorCleanupChild); +} + +TestInterruptErrorCleanupChild::~TestInterruptErrorCleanupChild() { + MOZ_COUNT_DTOR(TestInterruptErrorCleanupChild); +} + +mozilla::ipc::IPCResult TestInterruptErrorCleanupChild::AnswerError() { + _exit(0); + MOZ_CRASH("unreached"); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h new file mode 100644 index 0000000000..9ae0493cf0 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h @@ -0,0 +1,52 @@ +#ifndef mozilla__ipdltest_TestInterruptErrorCleanup_h +#define mozilla__ipdltest_TestInterruptErrorCleanup_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestInterruptErrorCleanupParent.h" +#include "mozilla/_ipdltest/PTestInterruptErrorCleanupChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestInterruptErrorCleanupParent + : public PTestInterruptErrorCleanupParent { + public: + TestInterruptErrorCleanupParent(); + virtual ~TestInterruptErrorCleanupParent(); + + static bool RunTestInProcesses() { return true; } + // FIXME/bug 703323 Could work if modified + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + } + + virtual void ProcessingError(Result aCode, const char* aReason) override; + + bool mGotProcessingError; +}; + +class TestInterruptErrorCleanupChild : public PTestInterruptErrorCleanupChild { + friend class PTestInterruptErrorCleanupChild; + + public: + TestInterruptErrorCleanupChild(); + virtual ~TestInterruptErrorCleanupChild(); + + protected: + mozilla::ipc::IPCResult AnswerError(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + fail("should have 'crashed'!"); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestInterruptErrorCleanup_h diff --git a/ipc/ipdl/test/cxx/TestInterruptRaces.cpp b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp new file mode 100644 index 0000000000..02b42cfbc3 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp @@ -0,0 +1,169 @@ +#include "TestInterruptRaces.h" + +#include "IPDLUnitTests.h" // fail etc. + +using mozilla::ipc::MessageChannel; + +namespace mozilla { +namespace _ipdltest { + +ipc::RacyInterruptPolicy MediateRace(const MessageChannel::MessageInfo& parent, + const MessageChannel::MessageInfo& child) { + return (PTestInterruptRaces::Msg_Child__ID == parent.type()) + ? ipc::RIPParentWins + : ipc::RIPChildWins; +} + +//----------------------------------------------------------------------------- +// parent +void TestInterruptRacesParent::Main() { + if (!SendStart()) fail("sending Start()"); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::RecvStartRace() { + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestInterruptRacesParent::OnRaceTime", this, + &TestInterruptRacesParent::OnRaceTime)); + return IPC_OK(); +} + +void TestInterruptRacesParent::OnRaceTime() { + if (!CallRace(&mChildHasReply)) fail("problem calling Race()"); + + if (!mChildHasReply) fail("child should have got a reply already"); + + mHasReply = true; + + MessageLoop::current()->PostTask( + NewNonOwningRunnableMethod("_ipdltest::TestInterruptRacesParent::Test2", + this, &TestInterruptRacesParent::Test2)); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerRace(bool* hasReply) { + if (mHasReply) fail("apparently the parent won the Interrupt race!"); + *hasReply = hasReply; + return IPC_OK(); +} + +void TestInterruptRacesParent::Test2() { + puts(" passed"); + puts("Test 2"); + + mHasReply = false; + mChildHasReply = false; + + if (!CallStackFrame()) fail("can't set up a stack frame"); + + puts(" passed"); + + MessageLoop::current()->PostTask( + NewNonOwningRunnableMethod("_ipdltest::TestInterruptRacesParent::Test3", + this, &TestInterruptRacesParent::Test3)); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerStackFrame() { + if (!SendWakeup()) fail("can't wake up the child"); + + if (!CallRace(&mChildHasReply)) fail("can't set up race condition"); + mHasReply = true; + + if (!mChildHasReply) fail("child should have got a reply already"); + + return IPC_OK(); +} + +void TestInterruptRacesParent::Test3() { + puts("Test 3"); + + if (!CallStackFrame3()) fail("can't set up a stack frame"); + + puts(" passed"); + + Close(); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerStackFrame3() { + if (!SendWakeup3()) fail("can't wake up the child"); + + if (!CallChild()) fail("can't set up race condition"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerParent() { + mAnsweredParent = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesParent::RecvGetAnsweredParent( + bool* answeredParent) { + *answeredParent = mAnsweredParent; + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child +mozilla::ipc::IPCResult TestInterruptRacesChild::RecvStart() { + puts("Test 1"); + + if (!SendStartRace()) fail("problem sending StartRace()"); + + bool dontcare; + if (!CallRace(&dontcare)) fail("problem calling Race()"); + + mHasReply = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerRace(bool* hasReply) { + if (!mHasReply) fail("apparently the child lost the Interrupt race!"); + + *hasReply = mHasReply; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerStackFrame() { + // reset for the second test + mHasReply = false; + + if (!CallStackFrame()) fail("can't set up stack frame"); + + if (!mHasReply) fail("should have had reply by now"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::RecvWakeup() { + bool dontcare; + if (!CallRace(&dontcare)) fail("can't set up race condition"); + + mHasReply = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerStackFrame3() { + if (!CallStackFrame3()) fail("can't set up stack frame"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::RecvWakeup3() { + if (!CallParent()) fail("can't set up race condition"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerChild() { + bool parentAnsweredParent; + // the parent is supposed to win the race, which means its + // message, Child(), is supposed to be processed before the + // child's message, Parent() + if (!SendGetAnsweredParent(&parentAnsweredParent)) + fail("sending GetAnsweredParent"); + + if (parentAnsweredParent) fail("parent was supposed to win the race!"); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestInterruptRaces.h b/ipc/ipdl/test/cxx/TestInterruptRaces.h new file mode 100644 index 0000000000..6fa184da1a --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptRaces.h @@ -0,0 +1,104 @@ +#ifndef mozilla__ipdltest_TestInterruptRaces_h +#define mozilla__ipdltest_TestInterruptRaces_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestInterruptRacesParent.h" +#include "mozilla/_ipdltest/PTestInterruptRacesChild.h" + +namespace mozilla { +namespace _ipdltest { + +mozilla::ipc::RacyInterruptPolicy MediateRace( + const mozilla::ipc::MessageChannel::MessageInfo& parent, + const mozilla::ipc::MessageChannel::MessageInfo& child); + +class TestInterruptRacesParent : public PTestInterruptRacesParent { + friend class PTestInterruptRacesParent; + + public: + TestInterruptRacesParent() + : mHasReply(false), mChildHasReply(false), mAnsweredParent(false) {} + virtual ~TestInterruptRacesParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvStartRace(); + + mozilla::ipc::IPCResult AnswerRace(bool* hasRace); + + mozilla::ipc::IPCResult AnswerStackFrame(); + + mozilla::ipc::IPCResult AnswerStackFrame3(); + + mozilla::ipc::IPCResult AnswerParent(); + + mozilla::ipc::IPCResult RecvGetAnsweredParent(bool* answeredParent); + + mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override { + return MediateRace(parent, child); + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + if (!(mHasReply && mChildHasReply)) fail("both sides should have replies!"); + passed("ok"); + QuitParent(); + } + + private: + void OnRaceTime(); + + void Test2(); + void Test3(); + + bool mHasReply; + bool mChildHasReply; + bool mAnsweredParent; +}; + +class TestInterruptRacesChild : public PTestInterruptRacesChild { + friend class PTestInterruptRacesChild; + + public: + TestInterruptRacesChild() : mHasReply(false) {} + virtual ~TestInterruptRacesChild() {} + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult AnswerRace(bool* hasRace); + + mozilla::ipc::IPCResult AnswerStackFrame(); + + mozilla::ipc::IPCResult AnswerStackFrame3(); + + mozilla::ipc::IPCResult RecvWakeup(); + + mozilla::ipc::IPCResult RecvWakeup3(); + + mozilla::ipc::IPCResult AnswerChild(); + + virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override { + return MediateRace(parent, child); + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + private: + bool mHasReply; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestInterruptRaces_h diff --git a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp new file mode 100644 index 0000000000..5482893995 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp @@ -0,0 +1,111 @@ +#include "TestInterruptShutdownRace.h" + +#include "base/task.h" +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +namespace { + +// NB: this test does its own shutdown, rather than going through +// QuitParent(), because it's testing degenerate edge cases + +void DeleteSubprocess() { + gSubprocess->Destroy(); + gSubprocess = nullptr; +} + +void Done() { + passed(__FILE__); + QuitParent(); +} + +} // namespace + +TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent() { + MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent); +} + +TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent() { + MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent); +} + +void TestInterruptShutdownRaceParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvStartDeath() { + // this will be ordered before the OnMaybeDequeueOne event of + // Orphan in the queue + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestInterruptShutdownRaceParent::StartShuttingDown", this, + &TestInterruptShutdownRaceParent::StartShuttingDown)); + return IPC_OK(); +} + +void TestInterruptShutdownRaceParent::StartShuttingDown() { + // NB: we sleep here to try and avoid receiving the Orphan message + // while waiting for the CallExit() reply. if we fail at that, it + // will cause the test to pass spuriously, because there won't be + // an OnMaybeDequeueOne task for Orphan + PR_Sleep(2000); + + if (CallExit()) fail("connection was supposed to be interrupted"); + + Close(); + + delete static_cast<TestInterruptShutdownRaceParent*>(gParentActor); + gParentActor = nullptr; + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction("DeleteSubprocess", DeleteSubprocess)); + + // this is ordered after the OnMaybeDequeueOne event in the queue + MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done)); + + // |this| has been deleted, be mindful +} + +mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvOrphan() { + // it would be nice to fail() here, but we'll process this message + // while waiting for the reply CallExit(). The OnMaybeDequeueOne + // task will still be in the queue, it just wouldn't have had any + // work to do, if we hadn't deleted ourself + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild() { + MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild); +} + +TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild() { + MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild); +} + +mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::RecvStart() { + if (!SendStartDeath()) fail("sending StartDeath"); + + // See comment in StartShuttingDown(): we want to send Orphan() + // while the parent is in its PR_Sleep() + PR_Sleep(1000); + + if (!SendOrphan()) fail("sending Orphan"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::AnswerExit() { + _exit(0); + MOZ_CRASH("unreached"); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h new file mode 100644 index 0000000000..17425fc06c --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h @@ -0,0 +1,56 @@ +#ifndef mozilla__ipdltest_TestInterruptShutdownRace_h +#define mozilla__ipdltest_TestInterruptShutdownRace_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestInterruptShutdownRaceParent.h" +#include "mozilla/_ipdltest/PTestInterruptShutdownRaceChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestInterruptShutdownRaceParent + : public PTestInterruptShutdownRaceParent { + public: + TestInterruptShutdownRaceParent(); + virtual ~TestInterruptShutdownRaceParent(); + + static bool RunTestInProcesses() { return true; } + // FIXME/bug 703323 Could work if modified + static bool RunTestInThreads() { return false; } + + void Main(); + + mozilla::ipc::IPCResult RecvStartDeath(); + + mozilla::ipc::IPCResult RecvOrphan(); + + protected: + void StartShuttingDown(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (AbnormalShutdown != why) fail("unexpected destruction!"); + } +}; + +class TestInterruptShutdownRaceChild : public PTestInterruptShutdownRaceChild { + friend class PTestInterruptShutdownRaceChild; + + public: + TestInterruptShutdownRaceChild(); + virtual ~TestInterruptShutdownRaceChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult AnswerExit(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + fail("should have 'crashed'!"); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestInterruptShutdownRace_h diff --git a/ipc/ipdl/test/cxx/TestJSON.cpp b/ipc/ipdl/test/cxx/TestJSON.cpp new file mode 100644 index 0000000000..42fac919d1 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestJSON.cpp @@ -0,0 +1,113 @@ +#include "TestJSON.h" + +#include "IPDLUnitTests.h" // fail etc. + +#define test_assert(_cond, _msg) \ + if (!(_cond)) fail(_msg) + +namespace mozilla { +namespace _ipdltest { + +static nsString String(const char* const str) { + return NS_ConvertUTF8toUTF16(str); +} + +static void Array123(nsTArray<JSONVariant>& a123) { + a123.AppendElement(1); + a123.AppendElement(2); + a123.AppendElement(3); + + test_assert(a123 == a123, "operator== is broken"); +} + +template <class HandleT> +JSONVariant MakeTestVariant(HandleT* handle) { + // In JS syntax: + // + // return [ + // undefined, null, true, 1.25, "test string", + // handle, + // [ 1, 2, 3 ], + // { "undefined" : undefined, + // "null" : null, + // "true" : true, + // "1.25" : 1.25, + // "string" : "string" + // "handle" : handle, + // "array" : [ 1, 2, 3 ] + // } + // ] + // + nsTArray<JSONVariant> outer; + + outer.AppendElement(void_t()); + outer.AppendElement(null_t()); + outer.AppendElement(true); + outer.AppendElement(1.25); + outer.AppendElement(String("test string")); + + outer.AppendElement(handle); + + nsTArray<JSONVariant> tmp; + Array123(tmp); + outer.AppendElement(tmp); + + nsTArray<KeyValue> obj; + obj.AppendElement(KeyValue(String("undefined"), void_t())); + obj.AppendElement(KeyValue(String("null"), null_t())); + obj.AppendElement(KeyValue(String("true"), true)); + obj.AppendElement(KeyValue(String("1.25"), 1.25)); + obj.AppendElement(KeyValue(String("string"), String("value"))); + obj.AppendElement(KeyValue(String("handle"), handle)); + nsTArray<JSONVariant> tmp2; + Array123(tmp2); + obj.AppendElement(KeyValue(String("array"), tmp2)); + + outer.AppendElement(obj); + + test_assert(outer == outer, "operator== is broken"); + + return JSONVariant(outer); +} + +//----------------------------------------------------------------------------- +// parent + +void TestJSONParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestJSONParent::RecvTest(const JSONVariant& i, + JSONVariant* o) { + test_assert(i == i, "operator== is broken"); + test_assert(i == MakeTestVariant(mKid), "inparam mangled en route"); + + *o = i; + + test_assert(i == *o, "operator= is broken"); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +mozilla::ipc::IPCResult TestJSONChild::RecvStart() { + if (!SendPTestHandleConstructor()) fail("sending Handle ctor"); + + JSONVariant i(MakeTestVariant(mKid)); + test_assert(i == i, "operator== is broken"); + test_assert(i == MakeTestVariant(mKid), "copy ctor is broken"); + + JSONVariant o; + if (!SendTest(i, &o)) fail("sending Test"); + + test_assert(i == o, "round-trip mangled input data"); + test_assert(o == MakeTestVariant(mKid), "outparam mangled en route"); + + Close(); + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestJSON.h b/ipc/ipdl/test/cxx/TestJSON.h new file mode 100644 index 0000000000..eaf7516525 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestJSON.h @@ -0,0 +1,93 @@ +#ifndef mozilla__ipdltest_TestJSON_h +#define mozilla__ipdltest_TestJSON_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestJSONParent.h" +#include "mozilla/_ipdltest/PTestJSONChild.h" + +#include "mozilla/_ipdltest/PTestHandleParent.h" +#include "mozilla/_ipdltest/PTestHandleChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestHandleParent : public PTestHandleParent { + public: + TestHandleParent() {} + virtual ~TestHandleParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestJSONParent : public PTestJSONParent { + friend class PTestJSONParent; + + public: + TestJSONParent() {} + virtual ~TestJSONParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvTest(const JSONVariant& i, JSONVariant* o); + + PTestHandleParent* AllocPTestHandleParent() { + return mKid = new TestHandleParent(); + } + + bool DeallocPTestHandleParent(PTestHandleParent* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + PTestHandleParent* mKid; +}; + +class TestHandleChild : public PTestHandleChild { + public: + TestHandleChild() {} + virtual ~TestHandleChild() {} +}; + +class TestJSONChild : public PTestJSONChild { + friend class PTestJSONChild; + + public: + TestJSONChild() {} + virtual ~TestJSONChild() {} + + protected: + mozilla::ipc::IPCResult RecvStart(); + + PTestHandleChild* AllocPTestHandleChild() { + return mKid = new TestHandleChild(); + } + + bool DeallocPTestHandleChild(PTestHandleChild* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + PTestHandleChild* mKid; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestJSON_h diff --git a/ipc/ipdl/test/cxx/TestLatency.cpp b/ipc/ipdl/test/cxx/TestLatency.cpp new file mode 100644 index 0000000000..f88d8ea644 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestLatency.cpp @@ -0,0 +1,210 @@ +#include "TestLatency.h" + +#include "IPDLUnitTests.h" // fail etc. + +// A ping/pong trial takes O(100us) or more, so if we don't have 10us +// resolution or better, the results will not be terribly useful +static const double kTimingResolutionCutoff = 0.00001; // 10us + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestLatencyParent::TestLatencyParent() + : mStart(), + mPPTimeTotal(), + mPP5TimeTotal(), + mRpcTimeTotal(), + mPPTrialsToGo(NR_TRIALS), + mPP5TrialsToGo(NR_TRIALS), + mNumChildProcessedCompressedSpams(0), + mWhichPong5(0) { + MOZ_COUNT_CTOR(TestLatencyParent); +} + +TestLatencyParent::~TestLatencyParent() { MOZ_COUNT_DTOR(TestLatencyParent); } + +void TestLatencyParent::Main() { + TimeDuration resolution = TimeDuration::Resolution(); + if (resolution.ToSeconds() > kTimingResolutionCutoff) { + puts(" (skipping TestLatency, timing resolution is too poor)"); + Close(); + return; + } + + printf(" timing resolution: %g seconds\n", resolution.ToSecondsSigDigits()); + + if (mozilla::ipc::LoggingEnabled()) + MOZ_CRASH( + "you really don't want to log all IPC messages during this test, trust " + "me"); + + PingPongTrial(); +} + +void TestLatencyParent::PingPongTrial() { + mStart = TimeStamp::Now(); + if (!SendPing()) fail("sending Ping()"); +} + +void TestLatencyParent::Ping5Pong5Trial() { + mStart = TimeStamp::Now(); + + if (!SendPing5() || !SendPing5() || !SendPing5() || !SendPing5() || + !SendPing5()) + fail("sending Ping5()"); +} + +mozilla::ipc::IPCResult TestLatencyParent::RecvPong() { + TimeDuration thisTrial = (TimeStamp::Now() - mStart); + mPPTimeTotal += thisTrial; + + if (0 == (mPPTrialsToGo % 1000)) + printf(" PP trial %d: %g\n", mPPTrialsToGo, + thisTrial.ToSecondsSigDigits()); + + if (--mPPTrialsToGo > 0) + PingPongTrial(); + else + Ping5Pong5Trial(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestLatencyParent::RecvPong5() { + ++mWhichPong5; + + if (mWhichPong5 < 5) { + return IPC_OK(); + } + + mWhichPong5 = 0; + + TimeDuration thisTrial = (TimeStamp::Now() - mStart); + mPP5TimeTotal += thisTrial; + + if (0 == (mPP5TrialsToGo % 1000)) + printf(" PP5 trial %d: %g\n", mPP5TrialsToGo, + thisTrial.ToSecondsSigDigits()); + + if (0 < --mPP5TrialsToGo) + Ping5Pong5Trial(); + else + RpcTrials(); + + return IPC_OK(); +} + +void TestLatencyParent::RpcTrials() { + TimeStamp start = TimeStamp::Now(); + for (int i = 0; i < NR_TRIALS; ++i) { + if (!CallRpc()) fail("can't call Rpc()"); + if (0 == (i % 1000)) printf(" Rpc trial %d\n", i); + } + mRpcTimeTotal = (TimeStamp::Now() - start); + + SpamTrial(); +} + +void TestLatencyParent::SpamTrial() { + TimeStamp start = TimeStamp::Now(); + for (int i = 0; i < NR_SPAMS - 1; ++i) { + if (!SendSpam()) fail("sending Spam()"); + if (0 == (i % 10000)) printf(" Spam trial %d\n", i); + } + + // Synchronize with the child process to ensure all messages have + // been processed. This adds the overhead of a reply message from + // child-->here, but should be insignificant compared to >> + // NR_SPAMS. + if (!CallSynchro()) fail("calling Synchro()"); + + mSpamTimeTotal = (TimeStamp::Now() - start); + + CompressedSpamTrial(); +} + +void TestLatencyParent::CompressedSpamTrial() { + for (int i = 0; i < NR_SPAMS; ++i) { + if (!SendCompressedSpam(i + 1)) fail("sending CompressedSpam()"); + if (0 == (i % 10000)) printf(" CompressedSpam trial %d\n", i); + } + + uint32_t lastSeqno; + if (!CallSynchro2(&lastSeqno, &mNumChildProcessedCompressedSpams)) + fail("calling Synchro2()"); + + if (lastSeqno != NR_SPAMS) + fail("last seqno was %u, expected %u", lastSeqno, NR_SPAMS); + + // NB: since this is testing an optimization, it's somewhat bogus. + // Need to make a warning if it actually intermittently fails in + // practice, which is doubtful. + if (!(mNumChildProcessedCompressedSpams < NR_SPAMS)) + fail("Didn't compress any messages?"); + + Exit(); +} + +void TestLatencyParent::Exit() { Close(); } + +//----------------------------------------------------------------------------- +// child + +TestLatencyChild::TestLatencyChild() + : mLastSeqno(0), mNumProcessedCompressedSpams(0), mWhichPing5(0) { + MOZ_COUNT_CTOR(TestLatencyChild); +} + +TestLatencyChild::~TestLatencyChild() { MOZ_COUNT_DTOR(TestLatencyChild); } + +mozilla::ipc::IPCResult TestLatencyChild::RecvPing() { + SendPong(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestLatencyChild::RecvPing5() { + ++mWhichPing5; + + if (mWhichPing5 < 5) { + return IPC_OK(); + } + + mWhichPing5 = 0; + + if (!SendPong5() || !SendPong5() || !SendPong5() || !SendPong5() || + !SendPong5()) + fail("sending Pong5()"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestLatencyChild::AnswerRpc() { return IPC_OK(); } + +mozilla::ipc::IPCResult TestLatencyChild::RecvSpam() { + // no-op + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro() { return IPC_OK(); } + +mozilla::ipc::IPCResult TestLatencyChild::RecvCompressedSpam( + const uint32_t& seqno) { + if (seqno <= mLastSeqno) + fail("compressed seqnos must monotonically increase"); + + mLastSeqno = seqno; + ++mNumProcessedCompressedSpams; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro2( + uint32_t* lastSeqno, uint32_t* numMessagesDispatched) { + *lastSeqno = mLastSeqno; + *numMessagesDispatched = mNumProcessedCompressedSpams; + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestLatency.h b/ipc/ipdl/test/cxx/TestLatency.h new file mode 100644 index 0000000000..687b107808 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestLatency.h @@ -0,0 +1,107 @@ +#ifndef mozilla__ipdltest_TestLatency_h +#define mozilla__ipdltest_TestLatency_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestLatencyParent.h" +#include "mozilla/_ipdltest/PTestLatencyChild.h" + +#include "mozilla/TimeStamp.h" + +#define NR_TRIALS 10000 +#define NR_SPAMS 25000 + +namespace mozilla { +namespace _ipdltest { + +class TestLatencyParent : public PTestLatencyParent { + friend class PTestLatencyParent; + + private: + typedef mozilla::TimeStamp TimeStamp; + typedef mozilla::TimeDuration TimeDuration; + + public: + TestLatencyParent(); + virtual ~TestLatencyParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvPong(); + mozilla::ipc::IPCResult RecvPong5(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + + passed( + "\n" + " average #ping-pong/sec: %g\n" + " average #ping5-pong5/sec: %g\n" + " average #RPC call-answer/sec: %g\n" + " average #spams/sec: %g\n" + " pct. spams compressed away: %g\n", + double(NR_TRIALS) / mPPTimeTotal.ToSecondsSigDigits(), + double(NR_TRIALS) / mPP5TimeTotal.ToSecondsSigDigits(), + double(NR_TRIALS) / mRpcTimeTotal.ToSecondsSigDigits(), + double(NR_SPAMS) / mSpamTimeTotal.ToSecondsSigDigits(), + 100.0 * (double(NR_SPAMS - mNumChildProcessedCompressedSpams) / + double(NR_SPAMS))); + + QuitParent(); + } + + private: + void PingPongTrial(); + void Ping5Pong5Trial(); + void RpcTrials(); + void SpamTrial(); + void CompressedSpamTrial(); + void Exit(); + + TimeStamp mStart; + TimeDuration mPPTimeTotal; + TimeDuration mPP5TimeTotal; + TimeDuration mRpcTimeTotal; + TimeDuration mSpamTimeTotal; + + int mPPTrialsToGo; + int mPP5TrialsToGo; + uint32_t mNumChildProcessedCompressedSpams; + uint32_t mWhichPong5; +}; + +class TestLatencyChild : public PTestLatencyChild { + friend class PTestLatencyChild; + + public: + TestLatencyChild(); + virtual ~TestLatencyChild(); + + protected: + mozilla::ipc::IPCResult RecvPing(); + mozilla::ipc::IPCResult RecvPing5(); + mozilla::ipc::IPCResult AnswerRpc(); + mozilla::ipc::IPCResult RecvSpam(); + mozilla::ipc::IPCResult AnswerSynchro(); + mozilla::ipc::IPCResult RecvCompressedSpam(const uint32_t& seqno); + mozilla::ipc::IPCResult AnswerSynchro2(uint32_t* lastSeqno, + uint32_t* numMessagesDispatched); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + uint32_t mLastSeqno; + uint32_t mNumProcessedCompressedSpams; + uint32_t mWhichPing5; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestLatency_h diff --git a/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp b/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp new file mode 100644 index 0000000000..77d5786cfa --- /dev/null +++ b/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp @@ -0,0 +1,83 @@ +#include "TestManyChildAllocs.h" + +#include "IPDLUnitTests.h" // fail etc. + +#define NALLOCS 10 + +namespace mozilla { +namespace _ipdltest { + +// parent code + +TestManyChildAllocsParent::TestManyChildAllocsParent() { + MOZ_COUNT_CTOR(TestManyChildAllocsParent); +} + +TestManyChildAllocsParent::~TestManyChildAllocsParent() { + MOZ_COUNT_DTOR(TestManyChildAllocsParent); +} + +void TestManyChildAllocsParent::Main() { + if (!SendGo()) fail("can't send Go()"); +} + +mozilla::ipc::IPCResult TestManyChildAllocsParent::RecvDone() { + // explicitly *not* cleaning up, so we can sanity-check IPDL's + // auto-shutdown/cleanup handling + Close(); + + return IPC_OK(); +} + +bool TestManyChildAllocsParent::DeallocPTestManyChildAllocsSubParent( + PTestManyChildAllocsSubParent* __a) { + delete __a; + return true; +} + +PTestManyChildAllocsSubParent* +TestManyChildAllocsParent::AllocPTestManyChildAllocsSubParent() { + return new TestManyChildAllocsSubParent(); +} + +// child code + +TestManyChildAllocsChild::TestManyChildAllocsChild() { + MOZ_COUNT_CTOR(TestManyChildAllocsChild); +} + +TestManyChildAllocsChild::~TestManyChildAllocsChild() { + MOZ_COUNT_DTOR(TestManyChildAllocsChild); +} + +mozilla::ipc::IPCResult TestManyChildAllocsChild::RecvGo() { + for (int i = 0; i < NALLOCS; ++i) { + PTestManyChildAllocsSubChild* child = + SendPTestManyChildAllocsSubConstructor(); + + if (!child) fail("can't send ctor()"); + + if (!child->SendHello()) fail("can't send Hello()"); + } + + size_t len = ManagedPTestManyChildAllocsSubChild().Count(); + if (NALLOCS != len) fail("expected %lu kids, got %lu", NALLOCS, len); + + if (!SendDone()) fail("can't send Done()"); + + return IPC_OK(); +} + +bool TestManyChildAllocsChild::DeallocPTestManyChildAllocsSubChild( + PTestManyChildAllocsSubChild* __a) { + delete __a; + return true; +} + +PTestManyChildAllocsSubChild* +TestManyChildAllocsChild::AllocPTestManyChildAllocsSubChild() { + return new TestManyChildAllocsSubChild(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestManyChildAllocs.h b/ipc/ipdl/test/cxx/TestManyChildAllocs.h new file mode 100644 index 0000000000..3da6461810 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestManyChildAllocs.h @@ -0,0 +1,82 @@ +#ifndef mozilla__ipdltest_TestManyChildAllocs_h +#define mozilla__ipdltest_TestManyChildAllocs_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestManyChildAllocsParent.h" +#include "mozilla/_ipdltest/PTestManyChildAllocsChild.h" + +#include "mozilla/_ipdltest/PTestManyChildAllocsSubParent.h" +#include "mozilla/_ipdltest/PTestManyChildAllocsSubChild.h" + +namespace mozilla { +namespace _ipdltest { + +// top-level protocol + +class TestManyChildAllocsParent : public PTestManyChildAllocsParent { + friend class PTestManyChildAllocsParent; + + public: + TestManyChildAllocsParent(); + virtual ~TestManyChildAllocsParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvDone(); + bool DeallocPTestManyChildAllocsSubParent(PTestManyChildAllocsSubParent* __a); + PTestManyChildAllocsSubParent* AllocPTestManyChildAllocsSubParent(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestManyChildAllocsChild : public PTestManyChildAllocsChild { + friend class PTestManyChildAllocsChild; + + public: + TestManyChildAllocsChild(); + virtual ~TestManyChildAllocsChild(); + + protected: + mozilla::ipc::IPCResult RecvGo(); + bool DeallocPTestManyChildAllocsSubChild(PTestManyChildAllocsSubChild* __a); + PTestManyChildAllocsSubChild* AllocPTestManyChildAllocsSubChild(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +// do-nothing sub-protocol actors + +class TestManyChildAllocsSubParent : public PTestManyChildAllocsSubParent { + friend class PTestManyChildAllocsSubParent; + + public: + TestManyChildAllocsSubParent() {} + virtual ~TestManyChildAllocsSubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} + mozilla::ipc::IPCResult RecvHello() { return IPC_OK(); } +}; + +class TestManyChildAllocsSubChild : public PTestManyChildAllocsSubChild { + public: + TestManyChildAllocsSubChild() {} + virtual ~TestManyChildAllocsSubChild() {} +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestManyChildAllocs_h diff --git a/ipc/ipdl/test/cxx/TestMultiMgrs.cpp b/ipc/ipdl/test/cxx/TestMultiMgrs.cpp new file mode 100644 index 0000000000..f09bb9ca7b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestMultiMgrs.cpp @@ -0,0 +1,83 @@ +#include "TestMultiMgrs.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "mozilla/ipc/ProtocolUtils.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +void TestMultiMgrsParent::Main() { + TestMultiMgrsLeftParent* leftie = new TestMultiMgrsLeftParent(); + if (!SendPTestMultiMgrsLeftConstructor(leftie)) fail("error sending ctor"); + + TestMultiMgrsRightParent* rightie = new TestMultiMgrsRightParent(); + if (!SendPTestMultiMgrsRightConstructor(rightie)) fail("error sending ctor"); + + TestMultiMgrsBottomParent* bottomL = new TestMultiMgrsBottomParent(); + if (!leftie->SendPTestMultiMgrsBottomConstructor(bottomL)) + fail("error sending ctor"); + + TestMultiMgrsBottomParent* bottomR = new TestMultiMgrsBottomParent(); + if (!rightie->SendPTestMultiMgrsBottomConstructor(bottomR)) + fail("error sending ctor"); + + if (!leftie->HasChild(bottomL)) + fail("leftie didn't have a child it was supposed to!"); + if (leftie->HasChild(bottomR)) fail("leftie had rightie's child!"); + + if (!rightie->HasChild(bottomR)) + fail("rightie didn't have a child it was supposed to!"); + if (rightie->HasChild(bottomL)) fail("rightie had rightie's child!"); + + if (!SendCheck()) fail("couldn't kick off the child-side check"); +} + +mozilla::ipc::IPCResult TestMultiMgrsParent::RecvOK() { + Close(); + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +mozilla::ipc::IPCResult +TestMultiMgrsLeftChild::RecvPTestMultiMgrsBottomConstructor( + PTestMultiMgrsBottomChild* actor) { + static_cast<TestMultiMgrsChild*>(Manager())->mBottomL = actor; + return IPC_OK(); +} + +mozilla::ipc::IPCResult +TestMultiMgrsRightChild::RecvPTestMultiMgrsBottomConstructor( + PTestMultiMgrsBottomChild* actor) { + static_cast<TestMultiMgrsChild*>(Manager())->mBottomR = actor; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestMultiMgrsChild::RecvCheck() { + if (1 != ManagedPTestMultiMgrsLeftChild().Count()) fail("where's leftie?"); + if (1 != ManagedPTestMultiMgrsRightChild().Count()) fail("where's rightie?"); + + TestMultiMgrsLeftChild* leftie = static_cast<TestMultiMgrsLeftChild*>( + LoneManagedOrNullAsserts(ManagedPTestMultiMgrsLeftChild())); + TestMultiMgrsRightChild* rightie = static_cast<TestMultiMgrsRightChild*>( + LoneManagedOrNullAsserts(ManagedPTestMultiMgrsRightChild())); + + if (!leftie->HasChild(mBottomL)) + fail("leftie didn't have a child it was supposed to!"); + if (leftie->HasChild(mBottomR)) fail("leftie had rightie's child!"); + + if (!rightie->HasChild(mBottomR)) + fail("rightie didn't have a child it was supposed to!"); + if (rightie->HasChild(mBottomL)) fail("rightie had leftie's child!"); + + if (!SendOK()) fail("couldn't send OK()"); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestMultiMgrs.h b/ipc/ipdl/test/cxx/TestMultiMgrs.h new file mode 100644 index 0000000000..71826d42a7 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestMultiMgrs.h @@ -0,0 +1,222 @@ +#ifndef mozilla__ipdltest_TestMultiMgrs_h +#define mozilla__ipdltest_TestMultiMgrs_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestMultiMgrsParent.h" +#include "mozilla/_ipdltest/PTestMultiMgrsChild.h" +#include "mozilla/_ipdltest/PTestMultiMgrsBottomParent.h" +#include "mozilla/_ipdltest/PTestMultiMgrsBottomChild.h" +#include "mozilla/_ipdltest/PTestMultiMgrsLeftParent.h" +#include "mozilla/_ipdltest/PTestMultiMgrsLeftChild.h" +#include "mozilla/_ipdltest/PTestMultiMgrsRightParent.h" +#include "mozilla/_ipdltest/PTestMultiMgrsRightChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Parent side +// + +class TestMultiMgrsBottomParent : public PTestMultiMgrsBottomParent { + public: + TestMultiMgrsBottomParent() {} + virtual ~TestMultiMgrsBottomParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestMultiMgrsLeftParent : public PTestMultiMgrsLeftParent { + friend class PTestMultiMgrsLeftParent; + + public: + TestMultiMgrsLeftParent() {} + virtual ~TestMultiMgrsLeftParent() {} + + bool HasChild(TestMultiMgrsBottomParent* c) { + return ManagedPTestMultiMgrsBottomParent().Contains(c); + } + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} + + PTestMultiMgrsBottomParent* AllocPTestMultiMgrsBottomParent() { + return new TestMultiMgrsBottomParent(); + } + + bool DeallocPTestMultiMgrsBottomParent(PTestMultiMgrsBottomParent* actor) { + delete actor; + return true; + } +}; + +class TestMultiMgrsRightParent : public PTestMultiMgrsRightParent { + friend class PTestMultiMgrsRightParent; + + public: + TestMultiMgrsRightParent() {} + virtual ~TestMultiMgrsRightParent() {} + + bool HasChild(TestMultiMgrsBottomParent* c) { + return ManagedPTestMultiMgrsBottomParent().Contains(c); + } + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override {} + + PTestMultiMgrsBottomParent* AllocPTestMultiMgrsBottomParent() { + return new TestMultiMgrsBottomParent(); + } + + bool DeallocPTestMultiMgrsBottomParent(PTestMultiMgrsBottomParent* actor) { + delete actor; + return true; + } +}; + +class TestMultiMgrsParent : public PTestMultiMgrsParent { + friend class PTestMultiMgrsParent; + + public: + TestMultiMgrsParent() {} + virtual ~TestMultiMgrsParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvOK(); + + PTestMultiMgrsLeftParent* AllocPTestMultiMgrsLeftParent() { + return new TestMultiMgrsLeftParent(); + } + + bool DeallocPTestMultiMgrsLeftParent(PTestMultiMgrsLeftParent* actor) { + delete actor; + return true; + } + + PTestMultiMgrsRightParent* AllocPTestMultiMgrsRightParent() { + return new TestMultiMgrsRightParent(); + } + + bool DeallocPTestMultiMgrsRightParent(PTestMultiMgrsRightParent* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +//----------------------------------------------------------------------------- +// Child side +// + +class TestMultiMgrsBottomChild : public PTestMultiMgrsBottomChild { + public: + TestMultiMgrsBottomChild() {} + virtual ~TestMultiMgrsBottomChild() {} +}; + +class TestMultiMgrsLeftChild : public PTestMultiMgrsLeftChild { + friend class PTestMultiMgrsLeftChild; + + public: + TestMultiMgrsLeftChild() {} + virtual ~TestMultiMgrsLeftChild() {} + + bool HasChild(PTestMultiMgrsBottomChild* c) { + return ManagedPTestMultiMgrsBottomChild().Contains(c); + } + + protected: + virtual mozilla::ipc::IPCResult RecvPTestMultiMgrsBottomConstructor( + PTestMultiMgrsBottomChild* actor) override; + + PTestMultiMgrsBottomChild* AllocPTestMultiMgrsBottomChild() { + return new TestMultiMgrsBottomChild(); + } + + bool DeallocPTestMultiMgrsBottomChild(PTestMultiMgrsBottomChild* actor) { + delete actor; + return true; + } +}; + +class TestMultiMgrsRightChild : public PTestMultiMgrsRightChild { + friend class PTestMultiMgrsRightChild; + + public: + TestMultiMgrsRightChild() {} + virtual ~TestMultiMgrsRightChild() {} + + bool HasChild(PTestMultiMgrsBottomChild* c) { + return ManagedPTestMultiMgrsBottomChild().Contains(c); + } + + protected: + virtual mozilla::ipc::IPCResult RecvPTestMultiMgrsBottomConstructor( + PTestMultiMgrsBottomChild* actor) override; + + PTestMultiMgrsBottomChild* AllocPTestMultiMgrsBottomChild() { + return new TestMultiMgrsBottomChild(); + } + + bool DeallocPTestMultiMgrsBottomChild(PTestMultiMgrsBottomChild* actor) { + delete actor; + return true; + } +}; + +class TestMultiMgrsChild : public PTestMultiMgrsChild { + friend class PTestMultiMgrsChild; + + public: + TestMultiMgrsChild() {} + virtual ~TestMultiMgrsChild() {} + + void Main(); + + PTestMultiMgrsBottomChild* mBottomL; + PTestMultiMgrsBottomChild* mBottomR; + + protected: + mozilla::ipc::IPCResult RecvCheck(); + + PTestMultiMgrsLeftChild* AllocPTestMultiMgrsLeftChild() { + return new TestMultiMgrsLeftChild(); + } + + bool DeallocPTestMultiMgrsLeftChild(PTestMultiMgrsLeftChild* actor) { + delete actor; + return true; + } + + PTestMultiMgrsRightChild* AllocPTestMultiMgrsRightChild() { + return new TestMultiMgrsRightChild(); + } + + bool DeallocPTestMultiMgrsRightChild(PTestMultiMgrsRightChild* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestMultiMgrs_h diff --git a/ipc/ipdl/test/cxx/TestNestedLoops.cpp b/ipc/ipdl/test/cxx/TestNestedLoops.cpp new file mode 100644 index 0000000000..3658d7dfb6 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestNestedLoops.cpp @@ -0,0 +1,78 @@ +#include "base/basictypes.h" + +#include "nsThreadUtils.h" + +#include "TestNestedLoops.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestNestedLoopsParent::TestNestedLoopsParent() : mBreakNestedLoop(false) { + MOZ_COUNT_CTOR(TestNestedLoopsParent); +} + +TestNestedLoopsParent::~TestNestedLoopsParent() { + MOZ_COUNT_DTOR(TestNestedLoopsParent); +} + +void TestNestedLoopsParent::Main() { + if (!SendStart()) fail("sending Start"); + + // sigh ... spin for a while to let Nonce arrive + puts(" (sleeping to wait for nonce ... sorry)"); + PR_Sleep(5000); + + // while waiting for the reply to R, we'll receive Nonce + if (!CallR()) fail("calling R"); + + Close(); +} + +mozilla::ipc::IPCResult TestNestedLoopsParent::RecvNonce() { + // if we have an OnMaybeDequeueOne waiting for us (we may not, due + // to the inherent race condition in this test, then this event + // must be ordered after it in the queue + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod( + "_ipdltest::TestNestedLoopsParent::BreakNestedLoop", this, + &TestNestedLoopsParent::BreakNestedLoop)); + + // sigh ... spin for a while to let the reply to R arrive + puts(" (sleeping to wait for reply to R ... sorry)"); + PR_Sleep(5000); + + // sigh ... we have no idea when code might do this + do { + if (!NS_ProcessNextEvent(nullptr, false)) + fail("expected at least one pending event"); + } while (!mBreakNestedLoop); + + return IPC_OK(); +} + +void TestNestedLoopsParent::BreakNestedLoop() { mBreakNestedLoop = true; } + +//----------------------------------------------------------------------------- +// child + +TestNestedLoopsChild::TestNestedLoopsChild() { + MOZ_COUNT_CTOR(TestNestedLoopsChild); +} + +TestNestedLoopsChild::~TestNestedLoopsChild() { + MOZ_COUNT_DTOR(TestNestedLoopsChild); +} + +mozilla::ipc::IPCResult TestNestedLoopsChild::RecvStart() { + if (!SendNonce()) fail("sending Nonce"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestNestedLoopsChild::AnswerR() { return IPC_OK(); } + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestNestedLoops.h b/ipc/ipdl/test/cxx/TestNestedLoops.h new file mode 100644 index 0000000000..001b571494 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestNestedLoops.h @@ -0,0 +1,59 @@ +#ifndef mozilla__ipdltest_TestNestedLoops_h +#define mozilla__ipdltest_TestNestedLoops_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestNestedLoopsParent.h" +#include "mozilla/_ipdltest/PTestNestedLoopsChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestNestedLoopsParent : public PTestNestedLoopsParent { + friend class PTestNestedLoopsParent; + + public: + TestNestedLoopsParent(); + virtual ~TestNestedLoopsParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvNonce(); + + void BreakNestedLoop(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + bool mBreakNestedLoop; +}; + +class TestNestedLoopsChild : public PTestNestedLoopsChild { + friend class PTestNestedLoopsChild; + + public: + TestNestedLoopsChild(); + virtual ~TestNestedLoopsChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult AnswerR(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestNestedLoops_h diff --git a/ipc/ipdl/test/cxx/TestRPC.cpp b/ipc/ipdl/test/cxx/TestRPC.cpp new file mode 100644 index 0000000000..404de01aa8 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRPC.cpp @@ -0,0 +1,107 @@ +#include "TestRPC.h" + +#include "IPDLUnitTests.h" // fail etc. +#if defined(OS_POSIX) +# include <unistd.h> +#else +# include <windows.h> +#endif + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestRPCParent::TestRPCParent() + : reentered_(false), resolved_first_cpow_(false) { + MOZ_COUNT_CTOR(TestRPCParent); +} + +TestRPCParent::~TestRPCParent() { MOZ_COUNT_DTOR(TestRPCParent); } + +void TestRPCParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestRPCParent::RecvTest1_Start(uint32_t* aResult) { + uint32_t result; + if (!SendTest1_InnerQuery(&result)) fail("SendTest1_InnerQuery"); + if (result != 300) fail("Wrong result (expected 300)"); + + *aResult = 100; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCParent::RecvTest1_InnerEvent(uint32_t* aResult) { + uint32_t result; + if (!SendTest1_NoReenter(&result)) fail("SendTest1_NoReenter"); + if (result != 400) fail("Wrong result (expected 400)"); + + *aResult = 200; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCParent::RecvTest2_Start() { + // Send a CPOW. During this time, we must NOT process the RPC message, as + // we could start receiving CPOW replies out-of-order. + if (!SendTest2_FirstUrgent()) fail("SendTest2_FirstUrgent"); + + MOZ_ASSERT(!reentered_); + resolved_first_cpow_ = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCParent::RecvTest2_OutOfOrder() { + // Send a CPOW. If this RPC call was initiated while waiting for the first + // CPOW to resolve, replies will be processed out of order, and we'll crash. + if (!SendTest2_SecondUrgent()) fail("SendTest2_SecondUrgent"); + + reentered_ = true; + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestRPCChild::TestRPCChild() { MOZ_COUNT_CTOR(TestRPCChild); } + +TestRPCChild::~TestRPCChild() { MOZ_COUNT_DTOR(TestRPCChild); } + +mozilla::ipc::IPCResult TestRPCChild::RecvStart() { + uint32_t result; + if (!SendTest1_Start(&result)) fail("SendTest1_Start"); + if (result != 100) fail("Wrong result (expected 100)"); + + if (!SendTest2_Start()) fail("SendTest2_Start"); + + if (!SendTest2_OutOfOrder()) fail("SendTest2_OutOfOrder"); + + Close(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCChild::RecvTest1_InnerQuery(uint32_t* aResult) { + uint32_t result; + if (!SendTest1_InnerEvent(&result)) fail("SendTest1_InnerEvent"); + if (result != 200) fail("Wrong result (expected 200)"); + + *aResult = 300; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult) { + *aResult = 400; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCChild::RecvTest2_FirstUrgent() { + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRPCChild::RecvTest2_SecondUrgent() { + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRPC.h b/ipc/ipdl/test/cxx/TestRPC.h new file mode 100644 index 0000000000..907d3fde36 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRPC.h @@ -0,0 +1,60 @@ +#ifndef mozilla__ipdltest_TestRPC_h +#define mozilla__ipdltest_TestRPC_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRPCParent.h" +#include "mozilla/_ipdltest/PTestRPCChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRPCParent : public PTestRPCParent { + public: + TestRPCParent(); + virtual ~TestRPCParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + mozilla::ipc::IPCResult RecvTest1_Start(uint32_t* aResult); + mozilla::ipc::IPCResult RecvTest1_InnerEvent(uint32_t* aResult); + mozilla::ipc::IPCResult RecvTest2_Start(); + mozilla::ipc::IPCResult RecvTest2_OutOfOrder(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + if (!reentered_) fail("never processed raced RPC call!"); + if (!resolved_first_cpow_) fail("never resolved first CPOW!"); + passed("ok"); + QuitParent(); + } + + private: + bool reentered_; + bool resolved_first_cpow_; +}; + +class TestRPCChild : public PTestRPCChild { + public: + TestRPCChild(); + virtual ~TestRPCChild(); + + mozilla::ipc::IPCResult RecvStart(); + mozilla::ipc::IPCResult RecvTest1_InnerQuery(uint32_t* aResult); + mozilla::ipc::IPCResult RecvTest1_NoReenter(uint32_t* aResult); + mozilla::ipc::IPCResult RecvTest2_FirstUrgent(); + mozilla::ipc::IPCResult RecvTest2_SecondUrgent(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRPC_h diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp new file mode 100644 index 0000000000..76defe97a5 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp @@ -0,0 +1,102 @@ +#include "TestRaceDeadlock.h" + +#include "IPDLUnitTests.h" // fail etc. + +// #define TEST_TIMEOUT 5000 + +using namespace mozilla::ipc; +typedef mozilla::ipc::MessageChannel::Message Message; +typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo; + +namespace mozilla { +namespace _ipdltest { + +static RacyInterruptPolicy MediateRace(const MessageInfo& parent, + const MessageInfo& child) { + return (PTestRaceDeadlock::Msg_Win__ID == parent.type()) ? RIPParentWins + : RIPChildWins; +} + +//----------------------------------------------------------------------------- +// parent + +TestRaceDeadlockParent::TestRaceDeadlockParent() { + MOZ_COUNT_CTOR(TestRaceDeadlockParent); +} + +TestRaceDeadlockParent::~TestRaceDeadlockParent() { + MOZ_COUNT_DTOR(TestRaceDeadlockParent); +} + +void TestRaceDeadlockParent::Main() { + Test1(); + + Close(); +} + +bool TestRaceDeadlockParent::ShouldContinueFromReplyTimeout() { + fail("This test should not hang"); + GetIPCChannel()->CloseWithTimeout(); + return false; +} + +void TestRaceDeadlockParent::Test1() { +#if defined(TEST_TIMEOUT) + SetReplyTimeoutMs(TEST_TIMEOUT); +#endif + if (!SendStartRace()) { + fail("sending StartRace"); + } + if (!CallRpc()) { + fail("calling Rpc"); + } +} + +mozilla::ipc::IPCResult TestRaceDeadlockParent::AnswerLose() { + return IPC_OK(); +} + +RacyInterruptPolicy TestRaceDeadlockParent::MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) { + return MediateRace(parent, child); +} + +//----------------------------------------------------------------------------- +// child + +TestRaceDeadlockChild::TestRaceDeadlockChild() { + MOZ_COUNT_CTOR(TestRaceDeadlockChild); +} + +TestRaceDeadlockChild::~TestRaceDeadlockChild() { + MOZ_COUNT_DTOR(TestRaceDeadlockChild); +} + +mozilla::ipc::IPCResult TestRaceDeadlockParent::RecvStartRace() { + if (!CallWin()) { + fail("calling Win"); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRaceDeadlockChild::RecvStartRace() { + if (!SendStartRace()) { + fail("calling SendStartRace"); + } + if (!CallLose()) { + fail("calling Lose"); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRaceDeadlockChild::AnswerWin() { return IPC_OK(); } + +mozilla::ipc::IPCResult TestRaceDeadlockChild::AnswerRpc() { return IPC_OK(); } + +RacyInterruptPolicy TestRaceDeadlockChild::MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) { + return MediateRace(parent, child); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.h b/ipc/ipdl/test/cxx/TestRaceDeadlock.h new file mode 100644 index 0000000000..2c5617130d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.h @@ -0,0 +1,68 @@ +#ifndef mozilla__ipdltest_TestRaceDeadlock_h +#define mozilla__ipdltest_TestRaceDeadlock_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRaceDeadlockParent.h" +#include "mozilla/_ipdltest/PTestRaceDeadlockChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRaceDeadlockParent : public PTestRaceDeadlockParent { + friend class PTestRaceDeadlockParent; + + public: + TestRaceDeadlockParent(); + virtual ~TestRaceDeadlockParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + virtual bool ShouldContinueFromReplyTimeout() override; + + void Test1(); + + mozilla::ipc::IPCResult RecvStartRace(); + mozilla::ipc::IPCResult AnswerLose(); + + virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestRaceDeadlockChild : public PTestRaceDeadlockChild { + friend class PTestRaceDeadlockChild; + + public: + TestRaceDeadlockChild(); + virtual ~TestRaceDeadlockChild(); + + protected: + mozilla::ipc::IPCResult RecvStartRace(); + + mozilla::ipc::IPCResult AnswerWin(); + + mozilla::ipc::IPCResult AnswerRpc(); + + virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRaceDeadlock_h diff --git a/ipc/ipdl/test/cxx/TestRaceDeferral.cpp b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp new file mode 100644 index 0000000000..c327b57c16 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp @@ -0,0 +1,84 @@ +#include "TestRaceDeferral.h" + +#include "IPDLUnitTests.h" // fail etc. + +using namespace mozilla::ipc; +typedef mozilla::ipc::MessageChannel::Message Message; +typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo; + +namespace mozilla { +namespace _ipdltest { + +static RacyInterruptPolicy MediateRace(const MessageInfo& parent, + const MessageInfo& child) { + return (PTestRaceDeferral::Msg_Win__ID == parent.type()) ? RIPParentWins + : RIPChildWins; +} + +//----------------------------------------------------------------------------- +// parent + +TestRaceDeferralParent::TestRaceDeferralParent() : mProcessedLose(false) { + MOZ_COUNT_CTOR(TestRaceDeferralParent); +} + +TestRaceDeferralParent::~TestRaceDeferralParent() { + MOZ_COUNT_DTOR(TestRaceDeferralParent); + + if (!mProcessedLose) fail("never processed Lose"); +} + +void TestRaceDeferralParent::Main() { + Test1(); + + Close(); +} + +void TestRaceDeferralParent::Test1() { + if (!SendStartRace()) fail("sending StartRace"); + + if (!CallWin()) fail("calling Win"); + if (mProcessedLose) fail("Lose didn't lose"); + + if (!CallRpc()) fail("calling Rpc"); + if (!mProcessedLose) fail("didn't resolve Rpc vs. Lose 'race' correctly"); +} + +mozilla::ipc::IPCResult TestRaceDeferralParent::AnswerLose() { + if (mProcessedLose) fail("processed Lose twice"); + mProcessedLose = true; + return IPC_OK(); +} + +RacyInterruptPolicy TestRaceDeferralParent::MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) { + return MediateRace(parent, child); +} + +//----------------------------------------------------------------------------- +// child + +TestRaceDeferralChild::TestRaceDeferralChild() { + MOZ_COUNT_CTOR(TestRaceDeferralChild); +} + +TestRaceDeferralChild::~TestRaceDeferralChild() { + MOZ_COUNT_DTOR(TestRaceDeferralChild); +} + +mozilla::ipc::IPCResult TestRaceDeferralChild::RecvStartRace() { + if (!CallLose()) fail("calling Lose"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRaceDeferralChild::AnswerWin() { return IPC_OK(); } + +mozilla::ipc::IPCResult TestRaceDeferralChild::AnswerRpc() { return IPC_OK(); } + +RacyInterruptPolicy TestRaceDeferralChild::MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) { + return MediateRace(parent, child); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRaceDeferral.h b/ipc/ipdl/test/cxx/TestRaceDeferral.h new file mode 100644 index 0000000000..b30264fb64 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeferral.h @@ -0,0 +1,67 @@ +#ifndef mozilla__ipdltest_TestRaceDeferral_h +#define mozilla__ipdltest_TestRaceDeferral_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRaceDeferralParent.h" +#include "mozilla/_ipdltest/PTestRaceDeferralChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRaceDeferralParent : public PTestRaceDeferralParent { + friend class PTestRaceDeferralParent; + + public: + TestRaceDeferralParent(); + virtual ~TestRaceDeferralParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + void Test1(); + + mozilla::ipc::IPCResult AnswerLose(); + + virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + bool mProcessedLose; +}; + +class TestRaceDeferralChild : public PTestRaceDeferralChild { + friend class PTestRaceDeferralChild; + + public: + TestRaceDeferralChild(); + virtual ~TestRaceDeferralChild(); + + protected: + mozilla::ipc::IPCResult RecvStartRace(); + + mozilla::ipc::IPCResult AnswerWin(); + + mozilla::ipc::IPCResult AnswerRpc(); + + virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace( + const MessageInfo& parent, const MessageInfo& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRaceDeferral_h diff --git a/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp new file mode 100644 index 0000000000..cda950b1a1 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp @@ -0,0 +1,94 @@ +#include "TestRacyInterruptReplies.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestRacyInterruptRepliesParent::TestRacyInterruptRepliesParent() + : mReplyNum(0) { + MOZ_COUNT_CTOR(TestRacyInterruptRepliesParent); +} + +TestRacyInterruptRepliesParent::~TestRacyInterruptRepliesParent() { + MOZ_COUNT_DTOR(TestRacyInterruptRepliesParent); +} + +void TestRacyInterruptRepliesParent::Main() { + int replyNum = -1; + if (!CallR_(&replyNum)) fail("calling R()"); + + if (1 != replyNum) fail("this should have been the first reply to R()"); + + if (!SendChildTest()) fail("sending ChildStart"); +} + +mozilla::ipc::IPCResult TestRacyInterruptRepliesParent::RecvA_() { + int replyNum = -1; + // this R() call races with the reply being generated by the other + // side to the R() call from Main(). This is a pretty nasty edge + // case for which one could argue we're breaking in-order message + // delivery, since this side will process the second reply to R() + // before the first. + if (!CallR_(&replyNum)) fail("calling R()"); + + if (2 != replyNum) fail("this should have been the second reply to R()"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyInterruptRepliesParent::Answer_R( + int* replyNum) { + *replyNum = ++mReplyNum; + + if (1 == *replyNum) + if (!Send_A()) fail("sending _A()"); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestRacyInterruptRepliesChild::TestRacyInterruptRepliesChild() : mReplyNum(0) { + MOZ_COUNT_CTOR(TestRacyInterruptRepliesChild); +} + +TestRacyInterruptRepliesChild::~TestRacyInterruptRepliesChild() { + MOZ_COUNT_DTOR(TestRacyInterruptRepliesChild); +} + +mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::AnswerR_(int* replyNum) { + *replyNum = ++mReplyNum; + + if (1 == *replyNum) SendA_(); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::RecvChildTest() { + int replyNum = -1; + if (!Call_R(&replyNum)) fail("calling R()"); + + if (1 != replyNum) fail("this should have been the first reply to R()"); + + Close(); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::Recv_A() { + int replyNum = -1; + + if (!Call_R(&replyNum)) fail("calling _R()"); + + if (2 != replyNum) fail("this should have been the second reply to R()"); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h new file mode 100644 index 0000000000..182c07f314 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h @@ -0,0 +1,65 @@ +#ifndef mozilla__ipdltest_TestRacyInterruptReplies_h +#define mozilla__ipdltest_TestRacyInterruptReplies_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRacyInterruptRepliesParent.h" +#include "mozilla/_ipdltest/PTestRacyInterruptRepliesChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRacyInterruptRepliesParent : public PTestRacyInterruptRepliesParent { + friend class PTestRacyInterruptRepliesParent; + + public: + TestRacyInterruptRepliesParent(); + virtual ~TestRacyInterruptRepliesParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvA_(); + + mozilla::ipc::IPCResult Answer_R(int* replyNum); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + private: + int mReplyNum; +}; + +class TestRacyInterruptRepliesChild : public PTestRacyInterruptRepliesChild { + friend class PTestRacyInterruptRepliesChild; + + public: + TestRacyInterruptRepliesChild(); + virtual ~TestRacyInterruptRepliesChild(); + + protected: + mozilla::ipc::IPCResult AnswerR_(int* replyNum); + + mozilla::ipc::IPCResult RecvChildTest(); + + mozilla::ipc::IPCResult Recv_A(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + private: + int mReplyNum; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRacyInterruptReplies_h diff --git a/ipc/ipdl/test/cxx/TestRacyReentry.cpp b/ipc/ipdl/test/cxx/TestRacyReentry.cpp new file mode 100644 index 0000000000..4224018e11 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyReentry.cpp @@ -0,0 +1,63 @@ +#include "TestRacyReentry.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestRacyReentryParent::TestRacyReentryParent() : mRecvdE(false) { + MOZ_COUNT_CTOR(TestRacyReentryParent); +} + +TestRacyReentryParent::~TestRacyReentryParent() { + MOZ_COUNT_DTOR(TestRacyReentryParent); +} + +void TestRacyReentryParent::Main() { + if (!SendStart()) fail("sending Start"); + + if (!SendN()) fail("sending N"); +} + +mozilla::ipc::IPCResult TestRacyReentryParent::AnswerE() { + if (!mRecvdE) { + mRecvdE = true; + return IPC_OK(); + } + + if (!CallH()) fail("calling H"); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestRacyReentryChild::TestRacyReentryChild() { + MOZ_COUNT_CTOR(TestRacyReentryChild); +} + +TestRacyReentryChild::~TestRacyReentryChild() { + MOZ_COUNT_DTOR(TestRacyReentryChild); +} + +mozilla::ipc::IPCResult TestRacyReentryChild::RecvStart() { + if (!CallE()) fail("calling E"); + + Close(); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyReentryChild::RecvN() { + if (!CallE()) fail("calling E"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyReentryChild::AnswerH() { return IPC_OK(); } + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRacyReentry.h b/ipc/ipdl/test/cxx/TestRacyReentry.h new file mode 100644 index 0000000000..e31f90c0e3 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyReentry.h @@ -0,0 +1,59 @@ +#ifndef mozilla__ipdltest_TestRacyReentry_h +#define mozilla__ipdltest_TestRacyReentry_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRacyReentryParent.h" +#include "mozilla/_ipdltest/PTestRacyReentryChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRacyReentryParent : public PTestRacyReentryParent { + friend class PTestRacyReentryParent; + + public: + TestRacyReentryParent(); + virtual ~TestRacyReentryParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult AnswerE(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + bool mRecvdE; +}; + +class TestRacyReentryChild : public PTestRacyReentryChild { + friend class PTestRacyReentryChild; + + public: + TestRacyReentryChild(); + virtual ~TestRacyReentryChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult RecvN(); + + mozilla::ipc::IPCResult AnswerH(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRacyReentry_h diff --git a/ipc/ipdl/test/cxx/TestRacyUndefer.cpp b/ipc/ipdl/test/cxx/TestRacyUndefer.cpp new file mode 100644 index 0000000000..a46db5618e --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyUndefer.cpp @@ -0,0 +1,83 @@ +#include "base/basictypes.h" + +#include "TestRacyUndefer.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestRacyUndeferParent::TestRacyUndeferParent() { + MOZ_COUNT_CTOR(TestRacyUndeferParent); +} + +TestRacyUndeferParent::~TestRacyUndeferParent() { + MOZ_COUNT_DTOR(TestRacyUndeferParent); +} + +void TestRacyUndeferParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestRacyUndeferParent::AnswerSpam() { + static bool spammed = false; + static bool raced = false; + if (!spammed) { + spammed = true; + + if (!SendAwakenSpam()) fail("sending AwakenSpam"); + } else if (!raced) { + raced = true; + + if (!SendAwakenRaceWinTwice()) fail("sending WinRaceTwice"); + + if (!CallRace()) fail("calling Race1"); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyUndeferParent::AnswerRaceWinTwice() { + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyUndeferParent::RecvDone() { + Close(); + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestRacyUndeferChild::TestRacyUndeferChild() { + MOZ_COUNT_CTOR(TestRacyUndeferChild); +} + +TestRacyUndeferChild::~TestRacyUndeferChild() { + MOZ_COUNT_DTOR(TestRacyUndeferChild); +} + +mozilla::ipc::IPCResult TestRacyUndeferChild::RecvStart() { + if (!CallSpam()) fail("calling Spam"); + + if (!SendDone()) fail("sending Done"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyUndeferChild::RecvAwakenSpam() { + if (!CallSpam()) fail("calling Spam"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyUndeferChild::RecvAwakenRaceWinTwice() { + if (!CallRaceWinTwice()) fail("calling RaceWinTwice"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestRacyUndeferChild::AnswerRace() { return IPC_OK(); } + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRacyUndefer.h b/ipc/ipdl/test/cxx/TestRacyUndefer.h new file mode 100644 index 0000000000..1e157a541b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRacyUndefer.h @@ -0,0 +1,62 @@ +#ifndef mozilla__ipdltest_TestRacyUndefer_h +#define mozilla__ipdltest_TestRacyUndefer_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRacyUndeferParent.h" +#include "mozilla/_ipdltest/PTestRacyUndeferChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRacyUndeferParent : public PTestRacyUndeferParent { + friend class PTestRacyUndeferParent; + + public: + TestRacyUndeferParent(); + virtual ~TestRacyUndeferParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult AnswerSpam(); + + mozilla::ipc::IPCResult AnswerRaceWinTwice(); + + mozilla::ipc::IPCResult RecvDone(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestRacyUndeferChild : public PTestRacyUndeferChild { + friend class PTestRacyUndeferChild; + + public: + TestRacyUndeferChild(); + virtual ~TestRacyUndeferChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult RecvAwakenSpam(); + mozilla::ipc::IPCResult RecvAwakenRaceWinTwice(); + + mozilla::ipc::IPCResult AnswerRace(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestRacyUndefer_h diff --git a/ipc/ipdl/test/cxx/TestSanity.cpp b/ipc/ipdl/test/cxx/TestSanity.cpp new file mode 100644 index 0000000000..ba1920fdcc --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSanity.cpp @@ -0,0 +1,52 @@ +#include "TestSanity.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestSanityParent::TestSanityParent() { MOZ_COUNT_CTOR(TestSanityParent); } + +TestSanityParent::~TestSanityParent() { MOZ_COUNT_DTOR(TestSanityParent); } + +void TestSanityParent::Main() { + if (!SendPing(0, 0.5f, 0)) fail("sending Ping"); +} + +mozilla::ipc::IPCResult TestSanityParent::RecvPong(const int& one, + const float& zeroPtTwoFive, + const uint8_t& /*unused*/) { + if (1 != one) fail("invalid argument `%d', should have been `1'", one); + + if (0.25f != zeroPtTwoFive) + fail("invalid argument `%g', should have been `0.25'", zeroPtTwoFive); + + Close(); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestSanityChild::TestSanityChild() { MOZ_COUNT_CTOR(TestSanityChild); } + +TestSanityChild::~TestSanityChild() { MOZ_COUNT_DTOR(TestSanityChild); } + +mozilla::ipc::IPCResult TestSanityChild::RecvPing(const int& zero, + const float& zeroPtFive, + const int8_t& /*unused*/) { + if (0 != zero) fail("invalid argument `%d', should have been `0'", zero); + + if (0.5f != zeroPtFive) + fail("invalid argument `%g', should have been `0.5'", zeroPtFive); + + if (!SendPong(1, 0.25f, 0)) fail("sending Pong"); + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSanity.h b/ipc/ipdl/test/cxx/TestSanity.h new file mode 100644 index 0000000000..ca29d67672 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSanity.h @@ -0,0 +1,55 @@ +#ifndef mozilla__ipdltest_TestSanity_h +#define mozilla__ipdltest_TestSanity_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestSanityParent.h" +#include "mozilla/_ipdltest/PTestSanityChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestSanityParent : public PTestSanityParent { + friend class PTestSanityParent; + + public: + TestSanityParent(); + virtual ~TestSanityParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvPong(const int& one, const float& zeroPtTwoFive, + const uint8_t& dummy); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestSanityChild : public PTestSanityChild { + friend class PTestSanityChild; + + public: + TestSanityChild(); + virtual ~TestSanityChild(); + + protected: + mozilla::ipc::IPCResult RecvPing(const int& zero, const float& zeroPtFive, + const int8_t& dummy); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestSanity_h diff --git a/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp b/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp new file mode 100644 index 0000000000..5e09aa4d7e --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp @@ -0,0 +1,54 @@ +#include "TestSelfManageRoot.h" + +#include "IPDLUnitTests.h" // fail etc. + +#define ASSERT(c) \ + do { \ + if (!(c)) fail(#c); \ + } while (0) + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +void TestSelfManageRootParent::Main() { + TestSelfManageParent* a = + static_cast<TestSelfManageParent*>(SendPTestSelfManageConstructor()); + if (!a) fail("constructing PTestSelfManage"); + + ASSERT(1 == ManagedPTestSelfManageParent().Count()); + + TestSelfManageParent* aa = + static_cast<TestSelfManageParent*>(a->SendPTestSelfManageConstructor()); + if (!aa) fail("constructing PTestSelfManage"); + + ASSERT(1 == ManagedPTestSelfManageParent().Count() && + 1 == a->ManagedPTestSelfManageParent().Count()); + + if (!PTestSelfManageParent::Send__delete__(aa)) + fail("destroying PTestSelfManage"); + ASSERT(Deletion == aa->mWhy && 1 == ManagedPTestSelfManageParent().Count() && + 0 == a->ManagedPTestSelfManageParent().Count()); + delete aa; + + aa = static_cast<TestSelfManageParent*>(a->SendPTestSelfManageConstructor()); + if (!aa) fail("constructing PTestSelfManage"); + + ASSERT(1 == ManagedPTestSelfManageParent().Count() && + 1 == a->ManagedPTestSelfManageParent().Count()); + + if (!PTestSelfManageParent::Send__delete__(a)) + fail("destroying PTestSelfManage"); + ASSERT(Deletion == a->mWhy && AncestorDeletion == aa->mWhy && + 0 == ManagedPTestSelfManageParent().Count() && + 0 == a->ManagedPTestSelfManageParent().Count()); + delete a; + delete aa; + + Close(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSelfManageRoot.h b/ipc/ipdl/test/cxx/TestSelfManageRoot.h new file mode 100644 index 0000000000..5cea09b10d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSelfManageRoot.h @@ -0,0 +1,117 @@ +#ifndef mozilla__ipdltest_TestSelfManageRoot_h +#define mozilla__ipdltest_TestSelfManageRoot_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestSelfManageRootParent.h" +#include "mozilla/_ipdltest/PTestSelfManageRootChild.h" +#include "mozilla/_ipdltest/PTestSelfManageParent.h" +#include "mozilla/_ipdltest/PTestSelfManageChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Parent side + +class TestSelfManageParent : public PTestSelfManageParent { + friend class PTestSelfManageParent; + + public: + MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageParent) + MOZ_COUNTED_DTOR_OVERRIDE(TestSelfManageParent) + + ActorDestroyReason mWhy; + + protected: + PTestSelfManageParent* AllocPTestSelfManageParent() { + return new TestSelfManageParent(); + } + + bool DeallocPTestSelfManageParent(PTestSelfManageParent* a) { return true; } + + virtual void ActorDestroy(ActorDestroyReason why) override { mWhy = why; } +}; + +class TestSelfManageRootParent : public PTestSelfManageRootParent { + friend class PTestSelfManageRootParent; + + public: + MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageRootParent) + virtual ~TestSelfManageRootParent() { + MOZ_COUNT_DTOR(TestSelfManageRootParent); + } + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + PTestSelfManageParent* AllocPTestSelfManageParent() { + return new TestSelfManageParent(); + } + + bool DeallocPTestSelfManageParent(PTestSelfManageParent* a) { return true; } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +//----------------------------------------------------------------------------- +// Child side + +class TestSelfManageChild : public PTestSelfManageChild { + friend class PTestSelfManageChild; + + public: + MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageChild) + MOZ_COUNTED_DTOR_OVERRIDE(TestSelfManageChild) + + protected: + PTestSelfManageChild* AllocPTestSelfManageChild() { + return new TestSelfManageChild(); + } + + bool DeallocPTestSelfManageChild(PTestSelfManageChild* a) { + delete a; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +class TestSelfManageRootChild : public PTestSelfManageRootChild { + friend class PTestSelfManageRootChild; + + public: + MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageRootChild) + virtual ~TestSelfManageRootChild() { + MOZ_COUNT_DTOR(TestSelfManageRootChild); + } + + void Main(); + + protected: + PTestSelfManageChild* AllocPTestSelfManageChild() { + return new TestSelfManageChild(); + } + + bool DeallocPTestSelfManageChild(PTestSelfManageChild* a) { + delete a; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestSelfManageRoot_h diff --git a/ipc/ipdl/test/cxx/TestShmem.cpp b/ipc/ipdl/test/cxx/TestShmem.cpp new file mode 100644 index 0000000000..0a778e5322 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestShmem.cpp @@ -0,0 +1,106 @@ +#include "TestShmem.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Parent + +void TestShmemParent::Main() { + Shmem mem; + Shmem unsafe; + + size_t size = 12345; + if (!AllocShmem(size, &mem)) fail("can't alloc shmem"); + if (!AllocUnsafeShmem(size, &unsafe)) fail("can't alloc shmem"); + + if (mem.Size<char>() != size) + fail("shmem is wrong size: expected %lu, got %lu", size, mem.Size<char>()); + if (unsafe.Size<char>() != size) + fail("shmem is wrong size: expected %lu, got %lu", size, + unsafe.Size<char>()); + + char* ptr = mem.get<char>(); + memcpy(ptr, "Hello!", sizeof("Hello!")); + + char* unsafeptr = unsafe.get<char>(); + memcpy(unsafeptr, "Hello!", sizeof("Hello!")); + + Shmem unsafecopy = unsafe; + if (!SendGive(std::move(mem), std::move(unsafe), size)) + fail("can't send Give()"); + + // uncomment the following line for a (nondeterministic) surprise! + // char c1 = *ptr; (void)c1; + + // uncomment the following line for a deterministic surprise! + // char c2 = *mem.get<char>(); (void)c2; + + // unsafe shmem gets rid of those checks + char uc1 = *unsafeptr; + (void)uc1; + char uc2 = *unsafecopy.get<char>(); + (void)uc2; +} + +mozilla::ipc::IPCResult TestShmemParent::RecvTake(Shmem&& mem, Shmem&& unsafe, + const size_t& expectedSize) { + if (mem.Size<char>() != expectedSize) + fail("expected shmem size %lu, but it has size %lu", expectedSize, + mem.Size<char>()); + if (unsafe.Size<char>() != expectedSize) + fail("expected shmem size %lu, but it has size %lu", expectedSize, + unsafe.Size<char>()); + + if (strcmp(mem.get<char>(), "And yourself!")) + fail("expected message was not written"); + if (strcmp(unsafe.get<char>(), "And yourself!")) + fail("expected message was not written"); + + if (!DeallocShmem(mem)) fail("DeallocShmem"); + if (!DeallocShmem(unsafe)) fail("DeallocShmem"); + + Close(); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// Child + +mozilla::ipc::IPCResult TestShmemChild::RecvGive(Shmem&& mem, Shmem&& unsafe, + const size_t& expectedSize) { + if (mem.Size<char>() != expectedSize) + fail("expected shmem size %lu, but it has size %lu", expectedSize, + mem.Size<char>()); + if (unsafe.Size<char>() != expectedSize) + fail("expected shmem size %lu, but it has size %lu", expectedSize, + unsafe.Size<char>()); + + if (strcmp(mem.get<char>(), "Hello!")) + fail("expected message was not written"); + if (strcmp(unsafe.get<char>(), "Hello!")) + fail("expected message was not written"); + + char* unsafeptr = unsafe.get<char>(); + + memcpy(mem.get<char>(), "And yourself!", sizeof("And yourself!")); + memcpy(unsafeptr, "And yourself!", sizeof("And yourself!")); + + Shmem unsafecopy = unsafe; + if (!SendTake(std::move(mem), std::move(unsafe), expectedSize)) + fail("can't send Take()"); + + // these checks also shouldn't fail in the child + char uc1 = *unsafeptr; + (void)uc1; + char uc2 = *unsafecopy.get<char>(); + (void)uc2; + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestShmem.h b/ipc/ipdl/test/cxx/TestShmem.h new file mode 100644 index 0000000000..4ef1f4fd7b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestShmem.h @@ -0,0 +1,55 @@ +#ifndef mozilla__ipdltest_TestShmem_h +#define mozilla__ipdltest_TestShmem_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestShmemParent.h" +#include "mozilla/_ipdltest/PTestShmemChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestShmemParent : public PTestShmemParent { + friend class PTestShmemParent; + + public: + TestShmemParent() {} + virtual ~TestShmemParent() {} + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvTake(Shmem&& mem, Shmem&& unsafe, + const size_t& expectedSize); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestShmemChild : public PTestShmemChild { + friend class PTestShmemChild; + + public: + TestShmemChild() {} + virtual ~TestShmemChild() {} + + protected: + mozilla::ipc::IPCResult RecvGive(Shmem&& mem, Shmem&& unsafe, + const size_t& expectedSize); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestShmem_h diff --git a/ipc/ipdl/test/cxx/TestShutdown.cpp b/ipc/ipdl/test/cxx/TestShutdown.cpp new file mode 100644 index 0000000000..502695bd88 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestShutdown.cpp @@ -0,0 +1,185 @@ +#include "TestShutdown.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Parent side +void TestShutdownParent::Main() { + if (!SendStart()) fail("sending Start()"); +} + +void TestShutdownParent::ActorDestroy(ActorDestroyReason why) { + if (AbnormalShutdown != why) fail("should have ended test with crash!"); + + passed("ok"); + + QuitParent(); +} + +void TestShutdownSubParent::ActorDestroy(ActorDestroyReason why) { + if (Manager()->ManagedPTestShutdownSubParent().Count() == 0) + fail("manager should still have managees!"); + + if (mExpectCrash && AbnormalShutdown != why) + fail("expected crash!"); + else if (!mExpectCrash && AbnormalShutdown == why) + fail("wasn't expecting crash!"); + + if (mExpectCrash && 0 == ManagedPTestShutdownSubsubParent().Count()) + fail("expected to *still* have kids"); +} + +void TestShutdownSubsubParent::ActorDestroy(ActorDestroyReason why) { + if (Manager()->ManagedPTestShutdownSubsubParent().Count() == 0) + fail("manager should still have managees!"); + + if (mExpectParentDeleted && AncestorDeletion != why) + fail("expected ParentDeleted == why"); + else if (!mExpectParentDeleted && AncestorDeletion == why) + fail("wasn't expecting parent delete"); +} + +//----------------------------------------------------------------------------- +// Child side + +mozilla::ipc::IPCResult TestShutdownChild::RecvStart() { + // test 1: alloc some actors and subactors, delete in + // managee-before-manager order + { + bool expectCrash = false, expectParentDeleted = false; + + PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash); + if (!c1) fail("problem sending ctor"); + + PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash); + if (!c2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c1s1 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c1s2 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c2s1 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c2s2 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s2) fail("problem sending ctor"); + + if (!PTestShutdownSubsubChild::Send__delete__(c1s1)) + fail("problem sending dtor"); + if (!PTestShutdownSubsubChild::Send__delete__(c1s2)) + fail("problem sending dtor"); + if (!PTestShutdownSubsubChild::Send__delete__(c2s1)) + fail("problem sending dtor"); + if (!PTestShutdownSubsubChild::Send__delete__(c2s2)) + fail("problem sending dtor"); + + if (!c1->CallStackFrame()) fail("problem creating dummy stack frame"); + if (!c2->CallStackFrame()) fail("problem creating dummy stack frame"); + } + + // test 2: alloc some actors and subactors, delete managers first + { + bool expectCrash = false, expectParentDeleted = true; + + PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash); + if (!c1) fail("problem sending ctor"); + + PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash); + if (!c2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c1s1 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c1s2 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c2s1 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c2s2 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s2) fail("problem sending ctor"); + + // delete parents without deleting kids + if (!c1->CallStackFrame()) fail("problem creating dummy stack frame"); + if (!c2->CallStackFrame()) fail("problem creating dummy stack frame"); + } + + // test 3: alloc some actors and subactors, then crash + { + bool expectCrash = true, expectParentDeleted = false; + + PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash); + if (!c1) fail("problem sending ctor"); + + PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash); + if (!c2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c1s1 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c1s2 = + c1->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c1s2) fail("problem sending ctor"); + + PTestShutdownSubsubChild* c2s1 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s1) fail("problem sending ctor"); + PTestShutdownSubsubChild* c2s2 = + c2->SendPTestShutdownSubsubConstructor(expectParentDeleted); + if (!c2s2) fail("problem sending ctor"); + + // make sure the ctors have been processed by the other side; + // the write end of the socket may temporarily be unwriteable + if (!SendSync()) fail("can't synchronize with parent"); + + // "crash", but without tripping tinderbox assert/abort + // detectors + _exit(0); + } +} + +void TestShutdownChild::ActorDestroy(ActorDestroyReason why) { + fail("hey wait ... we should have crashed!"); +} + +mozilla::ipc::IPCResult TestShutdownSubChild::AnswerStackFrame() { + if (!PTestShutdownSubChild::Send__delete__(this)) + fail("problem sending dtor"); + + // WATCH OUT! |this| has just deleted + + return IPC_OK(); +} + +void TestShutdownSubChild::ActorDestroy(ActorDestroyReason why) { + if (Manager()->ManagedPTestShutdownSubChild().Count() == 0) + fail("manager should still have managees!"); + + if (mExpectCrash && AbnormalShutdown != why) + fail("expected crash!"); + else if (!mExpectCrash && AbnormalShutdown == why) + fail("wasn't expecting crash!"); + + if (mExpectCrash && 0 == ManagedPTestShutdownSubsubChild().Count()) + fail("expected to *still* have kids"); +} + +void TestShutdownSubsubChild::ActorDestroy(ActorDestroyReason why) { + if (Manager()->ManagedPTestShutdownSubsubChild().Count() == 0) + fail("manager should still have managees!"); + + if (mExpectParentDeleted && AncestorDeletion != why) + fail("expected ParentDeleted == why"); + else if (!mExpectParentDeleted && AncestorDeletion == why) + fail("wasn't expecting parent delete"); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestShutdown.h b/ipc/ipdl/test/cxx/TestShutdown.h new file mode 100644 index 0000000000..224e42496d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestShutdown.h @@ -0,0 +1,168 @@ +#ifndef mozilla__ipdltest_TestShutdown_h +#define mozilla__ipdltest_TestShutdown_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestShutdownParent.h" +#include "mozilla/_ipdltest/PTestShutdownChild.h" + +#include "mozilla/_ipdltest/PTestShutdownSubParent.h" +#include "mozilla/_ipdltest/PTestShutdownSubChild.h" + +#include "mozilla/_ipdltest/PTestShutdownSubsubParent.h" +#include "mozilla/_ipdltest/PTestShutdownSubsubChild.h" + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// Parent side + +class TestShutdownSubsubParent : public PTestShutdownSubsubParent { + public: + explicit TestShutdownSubsubParent(bool expectParentDeleted) + : mExpectParentDeleted(expectParentDeleted) {} + + virtual ~TestShutdownSubsubParent() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override; + + private: + bool mExpectParentDeleted; +}; + +class TestShutdownSubParent : public PTestShutdownSubParent { + friend class PTestShutdownSubParent; + + public: + explicit TestShutdownSubParent(bool expectCrash) + : mExpectCrash(expectCrash), mDeletedCount(0) {} + + virtual ~TestShutdownSubParent() { + if (2 != mDeletedCount) fail("managees outliving manager!"); + } + + protected: + mozilla::ipc::IPCResult AnswerStackFrame() { + if (!CallStackFrame()) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); + } + + PTestShutdownSubsubParent* AllocPTestShutdownSubsubParent( + const bool& expectParentDelete) { + return new TestShutdownSubsubParent(expectParentDelete); + } + + bool DeallocPTestShutdownSubsubParent(PTestShutdownSubsubParent* actor) { + delete actor; + ++mDeletedCount; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override; + + private: + bool mExpectCrash; + int mDeletedCount; +}; + +class TestShutdownParent : public PTestShutdownParent { + friend class PTestShutdownParent; + + public: + TestShutdownParent() {} + virtual ~TestShutdownParent() {} + + static bool RunTestInProcesses() { return true; } + // FIXME/bug 703323 Could work if modified + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvSync() { return IPC_OK(); } + + PTestShutdownSubParent* AllocPTestShutdownSubParent(const bool& expectCrash) { + return new TestShutdownSubParent(expectCrash); + } + + bool DeallocPTestShutdownSubParent(PTestShutdownSubParent* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +//----------------------------------------------------------------------------- +// Child side + +class TestShutdownSubsubChild : public PTestShutdownSubsubChild { + public: + explicit TestShutdownSubsubChild(bool expectParentDeleted) + : mExpectParentDeleted(expectParentDeleted) {} + virtual ~TestShutdownSubsubChild() {} + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override; + + private: + bool mExpectParentDeleted; +}; + +class TestShutdownSubChild : public PTestShutdownSubChild { + friend class PTestShutdownSubChild; + + public: + explicit TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash) {} + + virtual ~TestShutdownSubChild() {} + + protected: + mozilla::ipc::IPCResult AnswerStackFrame(); + + PTestShutdownSubsubChild* AllocPTestShutdownSubsubChild( + const bool& expectParentDelete) { + return new TestShutdownSubsubChild(expectParentDelete); + } + + bool DeallocPTestShutdownSubsubChild(PTestShutdownSubsubChild* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override; + + private: + bool mExpectCrash; +}; + +class TestShutdownChild : public PTestShutdownChild { + friend class PTestShutdownChild; + + public: + TestShutdownChild() {} + virtual ~TestShutdownChild() {} + + protected: + mozilla::ipc::IPCResult RecvStart(); + + PTestShutdownSubChild* AllocPTestShutdownSubChild(const bool& expectCrash) { + return new TestShutdownSubChild(expectCrash); + } + + bool DeallocPTestShutdownSubChild(PTestShutdownSubChild* actor) { + delete actor; + return true; + } + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestShutdown_h diff --git a/ipc/ipdl/test/cxx/TestStackHooks.cpp b/ipc/ipdl/test/cxx/TestStackHooks.cpp new file mode 100644 index 0000000000..9800ac54e7 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestStackHooks.cpp @@ -0,0 +1,122 @@ +#include "TestStackHooks.h" + +#include "base/task.h" +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestStackHooksParent::TestStackHooksParent() + : mOnStack(false), mIncallDepth(0) { + MOZ_COUNT_CTOR(TestStackHooksParent); +} + +TestStackHooksParent::~TestStackHooksParent() { + MOZ_COUNT_DTOR(TestStackHooksParent); +} + +void TestStackHooksParent::Main() { + if (!SendStart()) fail("sending Start()"); +} + +mozilla::ipc::IPCResult TestStackHooksParent::AnswerStackFrame() { + if (!mOnStack) fail("not on C++ stack?!"); + + if (!CallStackFrame()) fail("calling StackFrame()"); + + if (!mOnStack) fail("not on C++ stack?!"); + + if (1 != mIncallDepth) fail("missed EnteredCall or ExitedCall hook"); + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestStackHooksChild::TestStackHooksChild() + : mOnStack(false), + mEntered(0), + mExited(0), + mIncallDepth(0), + mNumAnswerStackFrame(0) { + MOZ_COUNT_CTOR(TestStackHooksChild); +} + +TestStackHooksChild::~TestStackHooksChild() { + MOZ_COUNT_DTOR(TestStackHooksChild); +} + +namespace { +void RunTestsFn() { + static_cast<TestStackHooksChild*>(gChildActor)->RunTests(); +} +} // namespace + +mozilla::ipc::IPCResult TestStackHooksChild::RecvStart() { + if (!mOnStack) fail("missed stack notification"); + + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + + // kick off tests from a runnable so that we can start with + // MessageChannel code on the C++ stack + MessageLoop::current()->PostTask( + NewRunnableFunction("RunTestsFn", RunTestsFn)); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestStackHooksChild::AnswerStackFrame() { + ++mNumAnswerStackFrame; + + if (!mOnStack) fail("missed stack notification"); + + if (1 != mIncallDepth) fail("missed EnteredCall or ExitedCall hook"); + + if (mNumAnswerStackFrame == 1) { + if (!SendAsync()) fail("sending Async()"); + } else if (mNumAnswerStackFrame == 2) { + if (!SendSync()) fail("sending Sync()"); + } else { + fail("unexpected state"); + } + + if (!mOnStack) fail("bad stack exit notification"); + + return IPC_OK(); +} + +void TestStackHooksChild::RunTests() { + // 1 because of RecvStart() + if (1 != mEntered) fail("missed stack notification"); + if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + + if (!SendAsync()) fail("sending Async()"); + if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + if (2 != mEntered) fail("missed stack notification"); + + if (!SendSync()) fail("sending Sync()"); + if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + if (3 != mEntered) fail("missed stack notification"); + + if (!CallRpc()) fail("calling RPC()"); + if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + if (4 != mEntered) fail("missed stack notification"); + + if (!CallStackFrame()) fail("calling StackFrame()"); + if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction"); + if (5 != mEntered) fail("missed stack notification"); + + Close(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestStackHooks.h b/ipc/ipdl/test/cxx/TestStackHooks.h new file mode 100644 index 0000000000..315a3c1ae5 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestStackHooks.h @@ -0,0 +1,107 @@ +#ifndef mozilla__ipdltest_TestStackHooks_h +#define mozilla__ipdltest_TestStackHooks_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestStackHooksParent.h" +#include "mozilla/_ipdltest/PTestStackHooksChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestStackHooksParent : public PTestStackHooksParent { + friend class PTestStackHooksParent; + + public: + TestStackHooksParent(); + virtual ~TestStackHooksParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvAsync() { + if (!mOnStack) fail("not on C++ stack?!"); + return IPC_OK(); + } + + mozilla::ipc::IPCResult RecvSync() { + if (!mOnStack) fail("not on C++ stack?!"); + return IPC_OK(); + } + + mozilla::ipc::IPCResult AnswerRpc() { + if (!mOnStack) fail("not on C++ stack?!"); + return IPC_OK(); + } + + mozilla::ipc::IPCResult AnswerStackFrame(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } + + virtual void EnteredCxxStack() override { mOnStack = true; } + virtual void ExitedCxxStack() override { mOnStack = false; } + + virtual void EnteredCall() override { ++mIncallDepth; } + virtual void ExitedCall() override { --mIncallDepth; } + + private: + bool mOnStack; + int mIncallDepth; +}; + +class TestStackHooksChild : public PTestStackHooksChild { + friend class PTestStackHooksChild; + + public: + TestStackHooksChild(); + virtual ~TestStackHooksChild(); + + void RunTests(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult AnswerStackFrame(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + + if (mEntered != mExited) fail("unbalanced enter/exit notifications"); + + if (mOnStack) + fail("computing mOnStack went awry; should have failed above assertion"); + + QuitChild(); + } + + virtual void EnteredCxxStack() override { + ++mEntered; + mOnStack = true; + } + virtual void ExitedCxxStack() override { + ++mExited; + mOnStack = false; + } + + virtual void EnteredCall() override { ++mIncallDepth; } + virtual void ExitedCall() override { --mIncallDepth; } + + private: + bool mOnStack; + int mEntered; + int mExited; + int mIncallDepth; + int32_t mNumAnswerStackFrame; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestStackHooks_h diff --git a/ipc/ipdl/test/cxx/TestSyncError.cpp b/ipc/ipdl/test/cxx/TestSyncError.cpp new file mode 100644 index 0000000000..6c21590a87 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncError.cpp @@ -0,0 +1,45 @@ +#include "TestSyncError.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestSyncErrorParent::TestSyncErrorParent() { + MOZ_COUNT_CTOR(TestSyncErrorParent); +} + +TestSyncErrorParent::~TestSyncErrorParent() { + MOZ_COUNT_DTOR(TestSyncErrorParent); +} + +void TestSyncErrorParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestSyncErrorParent::RecvError() { + return IPC_FAIL_NO_REASON(this); +} + +//----------------------------------------------------------------------------- +// child + +TestSyncErrorChild::TestSyncErrorChild() { MOZ_COUNT_CTOR(TestSyncErrorChild); } + +TestSyncErrorChild::~TestSyncErrorChild() { + MOZ_COUNT_DTOR(TestSyncErrorChild); +} + +mozilla::ipc::IPCResult TestSyncErrorChild::RecvStart() { + if (SendError()) fail("Error() should have return false"); + + Close(); + + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSyncError.h b/ipc/ipdl/test/cxx/TestSyncError.h new file mode 100644 index 0000000000..8b84ed5e0b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncError.h @@ -0,0 +1,61 @@ +#ifndef mozilla__ipdltest_TestSyncError_h +#define mozilla__ipdltest_TestSyncError_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestSyncErrorParent.h" +#include "mozilla/_ipdltest/PTestSyncErrorChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestSyncErrorParent : public PTestSyncErrorParent { + friend class PTestSyncErrorParent; + + public: + TestSyncErrorParent(); + virtual ~TestSyncErrorParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult RecvError(); + + virtual void ProcessingError(Result aCode, const char* aReason) override { + // Ignore errors + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestSyncErrorChild : public PTestSyncErrorChild { + friend class PTestSyncErrorChild; + + public: + TestSyncErrorChild(); + virtual ~TestSyncErrorChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + virtual void ProcessingError(Result aCode, const char* aReason) override { + // Ignore errors + } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestSyncError_h diff --git a/ipc/ipdl/test/cxx/TestSyncHang.cpp b/ipc/ipdl/test/cxx/TestSyncHang.cpp new file mode 100644 index 0000000000..f53054787b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncHang.cpp @@ -0,0 +1,62 @@ +#include "TestSyncHang.h" +#include "base/task.h" +#include "mozilla/ipc/GeckoChildProcessHost.h" + +#include "IPDLUnitTests.h" // fail etc. + +using std::string; +using std::vector; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +mozilla::ipc::GeckoChildProcessHost* gSyncHangSubprocess; + +TestSyncHangParent::TestSyncHangParent() { MOZ_COUNT_CTOR(TestSyncHangParent); } + +TestSyncHangParent::~TestSyncHangParent() { + MOZ_COUNT_DTOR(TestSyncHangParent); +} + +void DeleteSyncHangSubprocess(MessageLoop* uiLoop) { + gSyncHangSubprocess->Destroy(); + gSyncHangSubprocess = nullptr; +} + +void DeferredSyncHangParentShutdown() { + // ping to DeleteSubprocess + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction("DeleteSyncHangSubprocess", DeleteSyncHangSubprocess, + MessageLoop::current())); +} + +void TestSyncHangParent::Main() { + vector<string> args; + args.push_back("fake/path"); + gSyncHangSubprocess = + new mozilla::ipc::GeckoChildProcessHost(GeckoProcessType_Plugin); + bool launched = gSyncHangSubprocess->SyncLaunch(args, 2); + if (launched) + fail("Calling SyncLaunch with an invalid path should return false"); + + MessageLoop::current()->PostTask(NewRunnableFunction( + "DeferredSyncHangParentShutdown", DeferredSyncHangParentShutdown)); + Close(); +} + +//----------------------------------------------------------------------------- +// child + +TestSyncHangChild::TestSyncHangChild() { MOZ_COUNT_CTOR(TestSyncHangChild); } + +TestSyncHangChild::~TestSyncHangChild() { MOZ_COUNT_DTOR(TestSyncHangChild); } + +mozilla::ipc::IPCResult TestSyncHangChild::RecvUnusedMessage() { + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSyncHang.h b/ipc/ipdl/test/cxx/TestSyncHang.h new file mode 100644 index 0000000000..911f05cd31 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncHang.h @@ -0,0 +1,50 @@ +#ifndef mozilla__ipdltest_TestSyncHang_h +#define mozilla__ipdltest_TestSyncHang_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestSyncHangParent.h" +#include "mozilla/_ipdltest/PTestSyncHangChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestSyncHangParent : public PTestSyncHangParent { + public: + TestSyncHangParent(); + virtual ~TestSyncHangParent(); + + static bool RunTestInProcesses() { return true; } + // FIXME/bug 703323 Could work if modified + static bool RunTestInThreads() { return false; } + + void Main(); + + protected: + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestSyncHangChild : public PTestSyncHangChild { + friend class PTestSyncHangChild; + + public: + TestSyncHangChild(); + virtual ~TestSyncHangChild(); + + protected: + mozilla::ipc::IPCResult RecvUnusedMessage(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestSyncHang_h diff --git a/ipc/ipdl/test/cxx/TestSyncWakeup.cpp b/ipc/ipdl/test/cxx/TestSyncWakeup.cpp new file mode 100644 index 0000000000..4c99aa1bab --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncWakeup.cpp @@ -0,0 +1,106 @@ +#if defined(OS_POSIX) +# include <unistd.h> // sleep() +#endif + +#include "TestSyncWakeup.h" + +#include "IPDLUnitTests.h" // fail etc. + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestSyncWakeupParent::TestSyncWakeupParent() { + MOZ_COUNT_CTOR(TestSyncWakeupParent); +} + +TestSyncWakeupParent::~TestSyncWakeupParent() { + MOZ_COUNT_DTOR(TestSyncWakeupParent); +} + +void TestSyncWakeupParent::Main() { + if (!SendStart()) fail("sending Start()"); +} + +mozilla::ipc::IPCResult TestSyncWakeupParent::AnswerStackFrame() { + if (!CallStackFrame()) fail("calling StackFrame()"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestSyncWakeupParent::RecvSync1() { + if (!SendNote1()) fail("sending Note1()"); + + // XXX ugh ... need to ensure that the async message and sync + // reply come in "far enough" apart that this test doesn't pass on + // accident +#if defined(OS_POSIX) + // NB: can't use PR_Sleep (i.e. Sleep() on windows) because it's + // only spec'd to block the current thread, not the current + // process. We need the IO thread to sleep as well. + puts(" (sleeping for 5 seconds. sorry!)"); + sleep(5); +#endif + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestSyncWakeupParent::RecvSync2() { + if (!SendNote2()) fail("sending Note2()"); + +#if defined(OS_POSIX) + // see above + sleep(5); + puts(" (sleeping for 5 seconds. sorry!)"); +#endif + + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +TestSyncWakeupChild::TestSyncWakeupChild() : mDone(false) { + MOZ_COUNT_CTOR(TestSyncWakeupChild); +} + +TestSyncWakeupChild::~TestSyncWakeupChild() { + MOZ_COUNT_DTOR(TestSyncWakeupChild); +} + +mozilla::ipc::IPCResult TestSyncWakeupChild::RecvStart() { + // First test: the parent fires back an async message while + // replying to a sync one + if (!SendSync1()) fail("sending Sync()"); + + // drop back into the event loop to get Note1(), then kick off the + // second test + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestSyncWakeupChild::RecvNote1() { + // Second test: the parent fires back an async message while + // replying to a sync one, with a frame on the RPC stack + if (!CallStackFrame()) fail("calling StackFrame()"); + + if (!mDone) fail("should have received Note2()!"); + + Close(); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestSyncWakeupChild::AnswerStackFrame() { + if (!SendSync2()) fail("sending Sync()"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestSyncWakeupChild::RecvNote2() { + mDone = true; + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSyncWakeup.h b/ipc/ipdl/test/cxx/TestSyncWakeup.h new file mode 100644 index 0000000000..5666307929 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestSyncWakeup.h @@ -0,0 +1,66 @@ +#ifndef mozilla__ipdltest_TestSyncWakeup_h +#define mozilla__ipdltest_TestSyncWakeup_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestSyncWakeupParent.h" +#include "mozilla/_ipdltest/PTestSyncWakeupChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestSyncWakeupParent : public PTestSyncWakeupParent { + friend class PTestSyncWakeupParent; + + public: + TestSyncWakeupParent(); + virtual ~TestSyncWakeupParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + + protected: + mozilla::ipc::IPCResult AnswerStackFrame(); + + mozilla::ipc::IPCResult RecvSync1(); + + mozilla::ipc::IPCResult RecvSync2(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + +class TestSyncWakeupChild : public PTestSyncWakeupChild { + friend class PTestSyncWakeupChild; + + public: + TestSyncWakeupChild(); + virtual ~TestSyncWakeupChild(); + + protected: + mozilla::ipc::IPCResult RecvStart(); + + mozilla::ipc::IPCResult RecvNote1(); + + mozilla::ipc::IPCResult AnswerStackFrame(); + + mozilla::ipc::IPCResult RecvNote2(); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) fail("unexpected destruction!"); + QuitChild(); + } + + private: + bool mDone; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestSyncWakeup_h diff --git a/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp b/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp new file mode 100644 index 0000000000..7d0e8dd6ca --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestUniquePtrIPC.h" + +namespace mozilla { +namespace _ipdltest { + +// --------------------------------------------------------------------------- +// PARENT PROCESS +// --------------------------------------------------------------------------- + +void TestUniquePtrIPCParent::Main() { + UniquePtr<int> a1 = MakeUnique<int>(1); + UniquePtr<DummyStruct> a2 = MakeUnique<DummyStruct>(2); + DummyStruct a3(3); + UniquePtr<int> a4; + + if (!SendTestMessage(std::move(a1), std::move(a2), a3, std::move(a4))) { + fail("failed sending UniquePtr items"); + } + + if (a1 || a2) { + fail("did not move TestMessage items in parent"); + } + + if (a4) { + fail("somehow turned null ptr into non-null by sending it"); + } + + // Pass UniquePtr by reference + UniquePtr<DummyStruct> b = MakeUnique<DummyStruct>(1); + + if (!SendTestSendReference(std::move(b))) { + fail("failed sending UniquePtr by reference"); + } + if (b) { + fail("did not move UniquePtr sent by reference"); + } +} + +// --------------------------------------------------------------------------- +// CHILD PROCESS +// --------------------------------------------------------------------------- + +mozilla::ipc::IPCResult TestUniquePtrIPCChild::RecvTestMessage( + UniquePtr<int>&& aA1, UniquePtr<DummyStruct>&& aA2, const DummyStruct& aA3, + UniquePtr<int>&& aA4) { + if ((!aA1) || (!aA2)) { + fail("TestMessage received NULL items in child"); + } + + if (aA4) { + fail("TestMessage received non-NULL when expecting NULL"); + } + + if ((*aA1 != 1) || (aA2->x() != 2) || (aA3.x() != 3)) { + fail("TestMessage received incorrect items in child"); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUniquePtrIPCChild::RecvTestSendReference( + UniquePtr<DummyStruct>&& aA) { + if (!aA) { + fail("TestSendReference received NULL item in child"); + } + + if (*aA != 1) { + fail("TestSendReference received incorrect item in child"); + } + + Close(); + return IPC_OK(); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestUniquePtrIPC.h b/ipc/ipdl/test/cxx/TestUniquePtrIPC.h new file mode 100644 index 0000000000..3c9de33df3 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUniquePtrIPC.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_TestUniquePtrIPC_h +#define mozilla_TestUniquePtrIPC_h + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestUniquePtrIPCParent.h" +#include "mozilla/_ipdltest/PTestUniquePtrIPCChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestUniquePtrIPCParent : public PTestUniquePtrIPCParent { + public: + MOZ_COUNTED_DEFAULT_CTOR(TestUniquePtrIPCParent) + MOZ_COUNTED_DTOR_OVERRIDE(TestUniquePtrIPCParent) + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + bool ShouldContinueFromReplyTimeout() override { return false; } + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) { + fail("Abnormal shutdown of parent"); + } + passed("ok"); + QuitParent(); + } +}; + +class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild { + public: + MOZ_COUNTED_DEFAULT_CTOR(TestUniquePtrIPCChild) + MOZ_COUNTED_DTOR_OVERRIDE(TestUniquePtrIPCChild) + + mozilla::ipc::IPCResult RecvTestMessage(UniquePtr<int>&& aA1, + UniquePtr<DummyStruct>&& aA2, + const DummyStruct& aA3, + UniquePtr<int>&& aA4); + + mozilla::ipc::IPCResult RecvTestSendReference(UniquePtr<DummyStruct>&& aA); + + virtual void ActorDestroy(ActorDestroyReason why) override { + if (NormalShutdown != why) { + fail("Abnormal shutdown of child"); + } + QuitChild(); + } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // mozilla_TestUniquePtrIPC_h diff --git a/ipc/ipdl/test/cxx/TestUrgency.cpp b/ipc/ipdl/test/cxx/TestUrgency.cpp new file mode 100644 index 0000000000..5845f8210d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUrgency.cpp @@ -0,0 +1,117 @@ +#include "TestUrgency.h" + +#include "IPDLUnitTests.h" // fail etc. +#if defined(OS_POSIX) +# include <unistd.h> +#else +# include <windows.h> +#endif + +namespace mozilla { +namespace _ipdltest { + +#if defined(OS_POSIX) +static void Sleep(int ms) { sleep(ms / 1000); } +#endif + +//----------------------------------------------------------------------------- +// parent + +TestUrgencyParent::TestUrgencyParent() : inreply_(false) { + MOZ_COUNT_CTOR(TestUrgencyParent); +} + +TestUrgencyParent::~TestUrgencyParent() { MOZ_COUNT_DTOR(TestUrgencyParent); } + +void TestUrgencyParent::Main() { + if (!SendStart()) fail("sending Start"); +} + +mozilla::ipc::IPCResult TestUrgencyParent::RecvTest1(uint32_t* value) { + if (!SendReply1(value)) fail("sending Reply1"); + if (*value != 99) fail("bad value"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgencyParent::RecvTest2() { + uint32_t value; + inreply_ = true; + if (!SendReply2(&value)) fail("sending Reply2"); + inreply_ = false; + if (value != 500) fail("bad value"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgencyParent::RecvTest3(uint32_t* value) { + if (inreply_) fail("nested non-urgent on top of urgent rpc"); + *value = 1000; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgencyParent::RecvFinalTest_Begin() { + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +enum { + kFirstTestBegin = 1, + kFirstTestGotReply, + kSecondTestBegin, + kSecondTestGotReply, +}; + +mozilla::ipc::IPCResult TestUrgencyChild::RecvStart() { + uint32_t result; + + // Send a synchronous message, expect to get an urgent message while + // blocked. + test_ = kFirstTestBegin; + if (!SendTest1(&result)) fail("calling SendTest1"); + if (result != 99) fail("bad result in RecvStart"); + if (test_ != kFirstTestGotReply) fail("never received urgent message"); + + // Initiate the next test by sending an asynchronous message, then becoming + // blocked. This tests that the urgent message is still delivered properly, + // and that the parent does not try to service the sync + test_ = kSecondTestBegin; + if (!SendTest2()) fail("calling SendTest2"); + if (!SendTest3(&result)) fail("calling SendTest3"); + if (test_ != kSecondTestGotReply) fail("never received urgent message #2"); + if (result != 1000) fail("wrong value from test3"); + + if (!SendFinalTest_Begin()) fail("Final test should have succeeded"); + + Close(); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgencyChild::RecvReply1(uint32_t* reply) { + if (test_ != kFirstTestBegin) fail("wrong test # in RecvReply1"); + + *reply = 99; + test_ = kFirstTestGotReply; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgencyChild::RecvReply2(uint32_t* reply) { + if (test_ != kSecondTestBegin) fail("wrong test # in RecvReply2"); + + // sleep for 5 seconds so the parent process tries to deliver more messages. + Sleep(5000); + + *reply = 500; + test_ = kSecondTestGotReply; + return IPC_OK(); +} + +TestUrgencyChild::TestUrgencyChild() : test_(0) { + MOZ_COUNT_CTOR(TestUrgencyChild); +} + +TestUrgencyChild::~TestUrgencyChild() { MOZ_COUNT_DTOR(TestUrgencyChild); } + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestUrgency.h b/ipc/ipdl/test/cxx/TestUrgency.h new file mode 100644 index 0000000000..6af73177ee --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUrgency.h @@ -0,0 +1,57 @@ +#ifndef mozilla__ipdltest_TestUrgency_h +#define mozilla__ipdltest_TestUrgency_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestUrgencyParent.h" +#include "mozilla/_ipdltest/PTestUrgencyChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestUrgencyParent : public PTestUrgencyParent { + public: + TestUrgencyParent(); + virtual ~TestUrgencyParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + + mozilla::ipc::IPCResult RecvTest1(uint32_t* value); + mozilla::ipc::IPCResult RecvTest2(); + mozilla::ipc::IPCResult RecvTest3(uint32_t* value); + mozilla::ipc::IPCResult RecvTest4_Begin(); + mozilla::ipc::IPCResult RecvTest4_NestedSync(); + mozilla::ipc::IPCResult RecvFinalTest_Begin(); + + bool ShouldContinueFromReplyTimeout() override { return false; } + virtual void ActorDestroy(ActorDestroyReason why) override { + passed("ok"); + QuitParent(); + } + + private: + bool inreply_; +}; + +class TestUrgencyChild : public PTestUrgencyChild { + public: + TestUrgencyChild(); + virtual ~TestUrgencyChild(); + + mozilla::ipc::IPCResult RecvStart(); + mozilla::ipc::IPCResult RecvReply1(uint32_t* reply); + mozilla::ipc::IPCResult RecvReply2(uint32_t* reply); + + virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); } + + private: + uint32_t test_; +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestUrgency_h diff --git a/ipc/ipdl/test/cxx/TestUrgentHangs.cpp b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp new file mode 100644 index 0000000000..e6139e38c5 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=2 ts=4 et : + */ +#include "TestUrgentHangs.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "prthread.h" +#if defined(OS_POSIX) +# include <unistd.h> +#else +# include <windows.h> +#endif + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +TestUrgentHangsParent::TestUrgentHangsParent() + : mInnerCount(0), mInnerUrgentCount(0) { + MOZ_COUNT_CTOR(TestUrgentHangsParent); +} + +TestUrgentHangsParent::~TestUrgentHangsParent() { + MOZ_COUNT_DTOR(TestUrgentHangsParent); +} + +void TestUrgentHangsParent::Main() { + SetReplyTimeoutMs(1000); + + // Should succeed despite the nested sleep call because the content process + // responded to the transaction. + if (!SendTest1_1()) fail("sending Test1_1"); + + // Fails with a timeout. + if (SendTest2()) fail("sending Test2"); + + // Also fails since we haven't gotten a response for Test2 yet. + if (SendTest3()) fail("sending Test3"); + + // Do a second round of testing once the reply to Test2 comes back. + MessageLoop::current()->PostDelayedTask( + NewNonOwningRunnableMethod( + "_ipdltest::TestUrgentHangsParent::SecondStage", this, + &TestUrgentHangsParent::SecondStage), + 3000); +} + +void TestUrgentHangsParent::SecondStage() { + // Send an async message that waits 2 seconds and then sends a sync message + // (which should be processed). + if (!SendTest4()) fail("sending Test4"); + + // Send a sync message that will time out because the child is waiting + // inside RecvTest4. + if (SendTest4_1()) fail("sending Test4_1"); + + MessageLoop::current()->PostDelayedTask( + NewNonOwningRunnableMethod("_ipdltest::TestUrgentHangsParent::ThirdStage", + this, &TestUrgentHangsParent::ThirdStage), + 3000); +} + +void TestUrgentHangsParent::ThirdStage() { + // The third stage does the same thing as the second stage except that the + // child sends an urgent message to us. In this case, we actually answer + // that message unconditionally. + + // Send an async message that waits 2 seconds and then sends a sync message + // (which should be processed). + if (!SendTest5()) fail("sending Test5"); + + // Send a sync message that will time out because the child is waiting + // inside RecvTest5. + if (SendTest5_1()) fail("sending Test5_1"); + + // Close the channel after the child finishes its work in RecvTest5. + MessageLoop::current()->PostDelayedTask( + NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this, + &TestUrgentHangsParent::Close), + 3000); +} + +mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTest1_2() { + if (!SendTest1_3()) fail("sending Test1_3"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTestInner() { + mInnerCount++; + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTestInnerUrgent() { + mInnerUrgentCount++; + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// child + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest1_1() { + if (!SendTest1_2()) fail("sending Test1_2"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest1_3() { + PR_Sleep(PR_SecondsToInterval(2)); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest2() { + PR_Sleep(PR_SecondsToInterval(2)); + + // Should fail because of the timeout. + if (SendTestInner()) fail("sending TestInner"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest3() { + fail("RecvTest3 should never be called"); + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest4() { + PR_Sleep(PR_SecondsToInterval(2)); + + // This won't fail because we should handle Test4_1 here before actually + // sending TestInner to the parent. + if (!SendTestInner()) fail("sending TestInner"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest4_1() { + // This should fail because Test4_1 timed out and hasn't gotten a response + // yet. + if (SendTestInner()) fail("sending TestInner"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest5() { + PR_Sleep(PR_SecondsToInterval(2)); + + // This message will actually be handled by the parent even though it's in + // the timeout state. + if (!SendTestInnerUrgent()) fail("sending TestInner"); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest5_1() { + // This message will actually be handled by the parent even though it's in + // the timeout state. + if (!SendTestInnerUrgent()) fail("sending TestInner"); + + return IPC_OK(); +} + +TestUrgentHangsChild::TestUrgentHangsChild() { + MOZ_COUNT_CTOR(TestUrgentHangsChild); +} + +TestUrgentHangsChild::~TestUrgentHangsChild() { + MOZ_COUNT_DTOR(TestUrgentHangsChild); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestUrgentHangs.h b/ipc/ipdl/test/cxx/TestUrgentHangs.h new file mode 100644 index 0000000000..facda522bf --- /dev/null +++ b/ipc/ipdl/test/cxx/TestUrgentHangs.h @@ -0,0 +1,64 @@ +#ifndef mozilla__ipdltest_TestUrgentHangs_h +#define mozilla__ipdltest_TestUrgentHangs_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestUrgentHangsParent.h" +#include "mozilla/_ipdltest/PTestUrgentHangsChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestUrgentHangsParent : public PTestUrgentHangsParent { + public: + TestUrgentHangsParent(); + virtual ~TestUrgentHangsParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return false; } + + void Main(); + void SecondStage(); + void ThirdStage(); + + mozilla::ipc::IPCResult RecvTest1_2(); + mozilla::ipc::IPCResult RecvTestInner(); + mozilla::ipc::IPCResult RecvTestInnerUrgent(); + + bool ShouldContinueFromReplyTimeout() override { return false; } + virtual void ActorDestroy(ActorDestroyReason why) override { + if (mInnerCount != 1) { + fail("wrong mInnerCount"); + } + if (mInnerUrgentCount != 2) { + fail("wrong mInnerUrgentCount"); + } + passed("ok"); + QuitParent(); + } + + private: + size_t mInnerCount, mInnerUrgentCount; +}; + +class TestUrgentHangsChild : public PTestUrgentHangsChild { + public: + TestUrgentHangsChild(); + virtual ~TestUrgentHangsChild(); + + mozilla::ipc::IPCResult RecvTest1_1(); + mozilla::ipc::IPCResult RecvTest1_3(); + mozilla::ipc::IPCResult RecvTest2(); + mozilla::ipc::IPCResult RecvTest3(); + mozilla::ipc::IPCResult RecvTest4(); + mozilla::ipc::IPCResult RecvTest4_1(); + mozilla::ipc::IPCResult RecvTest5(); + mozilla::ipc::IPCResult RecvTest5_1(); + + virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); } +}; + +} // namespace _ipdltest +} // namespace mozilla + +#endif // ifndef mozilla__ipdltest_TestUrgentHangs_h diff --git a/ipc/ipdl/test/cxx/app/TestIPDL.cpp b/ipc/ipdl/test/cxx/app/TestIPDL.cpp new file mode 100644 index 0000000000..3891aead62 --- /dev/null +++ b/ipc/ipdl/test/cxx/app/TestIPDL.cpp @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define MOZ_IPDL_TESTS +#include "mozilla/Bootstrap.h" + +#if defined(XP_WIN) +# include <windows.h> +# include "nsWindowsWMain.cpp" +#endif + +using namespace mozilla; + +int main(int argc, char** argv) { + // the first argument specifies which IPDL test case/suite to load + if (argc < 2) return 1; + + Bootstrap::UniquePtr bootstrap = GetBootstrap(); + if (!bootstrap) { + return 2; + } + return bootstrap->XRE_RunIPDLTest(argc, argv); +} diff --git a/ipc/ipdl/test/cxx/app/moz.build b/ipc/ipdl/test/cxx/app/moz.build new file mode 100644 index 0000000000..909360062a --- /dev/null +++ b/ipc/ipdl/test/cxx/app/moz.build @@ -0,0 +1,20 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +GeckoProgram("ipdlunittest", linkage="dependent") + +SOURCES += [ + "TestIPDL.cpp", +] +include("/ipc/chromium/chromium-config.mozbuild") + +LOCAL_INCLUDES += [ + "/toolkit/xre", + "/xpcom/base", +] + +if CONFIG["CC_TYPE"] == "clang-cl": + WIN32_EXE_LDFLAGS += ["-ENTRY:wmainCRTStartup"] diff --git a/ipc/ipdl/test/cxx/genIPDLUnitTests.py b/ipc/ipdl/test/cxx/genIPDLUnitTests.py new file mode 100644 index 0000000000..160b90a031 --- /dev/null +++ b/ipc/ipdl/test/cxx/genIPDLUnitTests.py @@ -0,0 +1,193 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import string +import sys + + +def usage(): + print( + """ +%s template_file -t unit_tests... -e extra_protocols... + + TEMPLATE_FILE is used to generate to generate the unit-tester .cpp + UNIT_TESTS are the top-level protocols defining unit tests + EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be + spawned in tests but are not unit tests in and of + themselves +""" + % (sys.argv[0]), + file=sys.stderr, + ) + sys.exit(1) + + +def main(argv): + template = argv[1] + + if argv[2] != "-t": + usage() + i = 3 + unittests = [] + while argv[i] != "-e": + unittests.append(argv[i]) + i += 1 + + extras = argv[(i + 1) :] + + includes = "\n".join(['#include "%s.h"' % (t) for t in unittests]) + + enum_values = "\n".join([" %s," % (t) for t in unittests + extras]) + last_enum = unittests[-1] + + string_to_enums = "\n".join( + [ + """ else if (!strcmp(aString, "%s")) + return %s;""" + % (t, t) + for t in unittests + extras + ] + ) + + enum_to_strings = "\n".join( + [ + """ case %s: + return "%s";""" + % (t, t) + for t in unittests + extras + ] + ) + + parent_delete_cases = "\n".join( + [ + """ case %s: { + delete reinterpret_cast<%sParent*>(gParentActor); + return; + } +""" + % (t, t) + for t in unittests + ] + ) + + parent_enabled_cases_proc = "\n".join( + [ + """ case %s: { + if (!%sParent::RunTestInProcesses()) { + passed("N/A to proc"); + DeferredParentShutdown(); + return; + } + break; + } +""" + % (t, t) + for t in unittests + ] + ) + + parent_main_cases_proc = "\n".join( + [ + """ case %s: { + %sParent** parent = + reinterpret_cast<%sParent**>(&gParentActor); + *parent = new %sParent(); + (*parent)->Open(transport, child); + return (*parent)->Main(); + } +""" + % (t, t, t, t) + for t in unittests + ] + ) + + parent_enabled_cases_thread = "\n".join( + [ + """ case %s: { + if (!%sParent::RunTestInThreads()) { + passed("N/A to threads"); + DeferredParentShutdown(); + return; + } + break; + } +""" + % (t, t) + for t in unittests + ] + ) + + parent_main_cases_thread = "\n".join( + [ + """ case %s: { + %sParent** parent = + reinterpret_cast<%sParent**>(&gParentActor); + *parent = new %sParent(); + + %sChild** child = + reinterpret_cast<%sChild**>(&gChildActor); + *child = new %sChild(); + + ::mozilla::ipc::MessageChannel *childChannel = (*child)->GetIPCChannel(); + ::mozilla::ipc::Side parentSide = + ::mozilla::ipc::ParentSide; + + (*parent)->Open(childChannel, childMessageLoop, parentSide); + return (*parent)->Main(); + } +""" + % (t, t, t, t, t, t, t) + for t in unittests + ] + ) + + child_delete_cases = "\n".join( + [ + """ case %s: { + delete reinterpret_cast<%sChild*>(gChildActor); + return; + } +""" + % (t, t) + for t in unittests + extras + ] + ) + + child_init_cases = "\n".join( + [ + """ case %s: { + %sChild** child = + reinterpret_cast<%sChild**>(&gChildActor); + *child = new %sChild(); + (*child)->Open(transport, parentPid, worker); + return; + } +""" + % (t, t, t, t) + for t in unittests + extras + ] + ) + + templatefile = open(template, "r", encoding="utf-8") + sys.stdout.write( + string.Template(templatefile.read()).substitute( + INCLUDES=includes, + ENUM_VALUES=enum_values, + LAST_ENUM=last_enum, + STRING_TO_ENUMS=string_to_enums, + ENUM_TO_STRINGS=enum_to_strings, + PARENT_DELETE_CASES=parent_delete_cases, + PARENT_ENABLED_CASES_PROC=parent_enabled_cases_proc, + PARENT_MAIN_CASES_PROC=parent_main_cases_proc, + PARENT_ENABLED_CASES_THREAD=parent_enabled_cases_thread, + PARENT_MAIN_CASES_THREAD=parent_main_cases_thread, + CHILD_DELETE_CASES=child_delete_cases, + CHILD_INIT_CASES=child_init_cases, + ) + ) + templatefile.close() + + +if __name__ == "__main__": + main(sys.argv) diff --git a/ipc/ipdl/test/cxx/moz.build b/ipc/ipdl/test/cxx/moz.build new file mode 100644 index 0000000000..e2650df0aa --- /dev/null +++ b/ipc/ipdl/test/cxx/moz.build @@ -0,0 +1,172 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ["app"] + +EXPORTS.mozilla._ipdltest += [ + "IPDLUnitTestProcessChild.h", + "IPDLUnitTests.h", + "IPDLUnitTestTypes.h", + "IPDLUnitTestUtils.h", + "TestActorPunning.h", + "TestAsyncReturns.h", + "TestBadActor.h", + "TestCancel.h", + "TestCrashCleanup.h", + "TestDataStructures.h", + "TestDemon.h", + "TestDesc.h", + "TestEndpointBridgeMain.h", + "TestEndpointOpens.h", + "TestFailedCtor.h", + "TestHangs.h", + "TestHighestPrio.h", + "TestInterruptErrorCleanup.h", + "TestInterruptRaces.h", + "TestInterruptShutdownRace.h", + "TestJSON.h", + "TestLatency.h", + "TestManyChildAllocs.h", + "TestMultiMgrs.h", + "TestNestedLoops.h", + "TestOffMainThreadPainting.h", + "TestRaceDeadlock.h", + "TestRaceDeferral.h", + "TestRacyInterruptReplies.h", + "TestRacyReentry.h", + "TestRacyUndefer.h", + "TestRPC.h", + "TestSanity.h", + "TestSelfManageRoot.h", + "TestShmem.h", + "TestShutdown.h", + "TestStackHooks.h", + "TestSyncError.h", + "TestSyncHang.h", + "TestSyncWakeup.h", + "TestUniquePtrIPC.h", + "TestUrgency.h", + "TestUrgentHangs.h", +] + +SOURCES += [ + "TestActorPunning.cpp", + "TestAsyncReturns.cpp", + "TestBadActor.cpp", + "TestCancel.cpp", + "TestCrashCleanup.cpp", + "TestDataStructures.cpp", + "TestDemon.cpp", + "TestDesc.cpp", + "TestEndpointBridgeMain.cpp", + "TestEndpointOpens.cpp", + "TestFailedCtor.cpp", + "TestHangs.cpp", + "TestHighestPrio.cpp", + "TestInterruptErrorCleanup.cpp", + "TestInterruptRaces.cpp", + "TestInterruptShutdownRace.cpp", + "TestJSON.cpp", + "TestLatency.cpp", + "TestManyChildAllocs.cpp", + "TestMultiMgrs.cpp", + "TestNestedLoops.cpp", + "TestOffMainThreadPainting.cpp", + "TestRaceDeadlock.cpp", + "TestRaceDeferral.cpp", + "TestRacyInterruptReplies.cpp", + "TestRacyReentry.cpp", + "TestRacyUndefer.cpp", + "TestRPC.cpp", + "TestSanity.cpp", + "TestSelfManageRoot.cpp", + "TestShmem.cpp", + "TestShutdown.cpp", + "TestStackHooks.cpp", + "TestSyncError.cpp", + "TestSyncHang.cpp", + "TestSyncWakeup.cpp", + "TestUniquePtrIPC.cpp", + "TestUrgency.cpp", + "TestUrgentHangs.cpp", +] + +SOURCES += [ + "!IPDLUnitTests.cpp", + "IPDLUnitTestProcessChild.cpp", + "IPDLUnitTestSubprocess.cpp", +] + +IPDL_SOURCES += [ + "PTestActorPunning.ipdl", + "PTestActorPunningPunned.ipdl", + "PTestActorPunningSub.ipdl", + "PTestAsyncReturns.ipdl", + "PTestBadActor.ipdl", + "PTestBadActorSub.ipdl", + "PTestCancel.ipdl", + "PTestCrashCleanup.ipdl", + "PTestDataStructures.ipdl", + "PTestDataStructuresCommon.ipdlh", + "PTestDataStructuresSub.ipdl", + "PTestDemon.ipdl", + "PTestDesc.ipdl", + "PTestDescSub.ipdl", + "PTestDescSubsub.ipdl", + "PTestEndpointBridgeMain.ipdl", + "PTestEndpointBridgeMainSub.ipdl", + "PTestEndpointBridgeSub.ipdl", + "PTestEndpointOpens.ipdl", + "PTestEndpointOpensOpened.ipdl", + "PTestFailedCtor.ipdl", + "PTestFailedCtorSub.ipdl", + "PTestFailedCtorSubsub.ipdl", + "PTestHandle.ipdl", + "PTestHangs.ipdl", + "PTestHighestPrio.ipdl", + "PTestIndirectProtocolParam.ipdlh", + "PTestIndirectProtocolParamFirst.ipdl", + "PTestIndirectProtocolParamManage.ipdl", + "PTestIndirectProtocolParamSecond.ipdl", + "PTestInterruptErrorCleanup.ipdl", + "PTestInterruptRaces.ipdl", + "PTestInterruptShutdownRace.ipdl", + "PTestJSON.ipdl", + "PTestLatency.ipdl", + "PTestManyChildAllocs.ipdl", + "PTestManyChildAllocsSub.ipdl", + "PTestMultiMgrs.ipdl", + "PTestMultiMgrsBottom.ipdl", + "PTestMultiMgrsLeft.ipdl", + "PTestMultiMgrsRight.ipdl", + "PTestNestedLoops.ipdl", + "PTestPaintThread.ipdl", + "PTestPriority.ipdl", + "PTestRaceDeadlock.ipdl", + "PTestRaceDeferral.ipdl", + "PTestRacyInterruptReplies.ipdl", + "PTestRacyReentry.ipdl", + "PTestRacyUndefer.ipdl", + "PTestRPC.ipdl", + "PTestSanity.ipdl", + "PTestSelfManage.ipdl", + "PTestSelfManageRoot.ipdl", + "PTestShmem.ipdl", + "PTestShutdown.ipdl", + "PTestShutdownSub.ipdl", + "PTestShutdownSubsub.ipdl", + "PTestStackHooks.ipdl", + "PTestSyncError.ipdl", + "PTestSyncHang.ipdl", + "PTestSyncWakeup.ipdl", + "PTestUniquePtrIPC.ipdl", + "PTestUrgency.ipdl", + "PTestUrgentHangs.ipdl", +] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" |