summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test/cxx/TestEndpointOpens.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/test/cxx/TestEndpointOpens.cpp')
-rw-r--r--ipc/ipdl/test/cxx/TestEndpointOpens.cpp242
1 files changed, 242 insertions, 0 deletions
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