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