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