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.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/TestHangs.cpp b/ipc/ipdl/test/cxx/TestHangs.cpp
new file mode 100644
index 000000000..b96823aee
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHangs.cpp
@@ -0,0 +1,146 @@
+#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)
+{
+ 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(this, &TestHangsParent::CleanUp));
+
+ GetIPCChannel()->CloseWithTimeout();
+
+ return false;
+}
+
+bool
+TestHangsParent::AnswerStackFrame()
+{
+ if (PTestHangs::HANG != state()) {
+ if (CallStackFrame())
+ fail("should have timed out!");
+ }
+ else {
+ // 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!");
+ }
+
+ return true;
+}
+
+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);
+}
+
+bool
+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 true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla