Test for bug 538586.
authorChris Jones <jones.chris.g@gmail.com>
Tue, 12 Jan 2010 00:14:31 -0600
changeset 37197 5468db693bfc0d9773e465cf0bbec7d0fec89cb4
parent 37196 a87c38ac059784c46d501bd9530148f5a8cdd967
child 37198 ea2bc4204d830d066ee15fbcd4e93c98b0d5527c
push id11168
push userbsmedberg@mozilla.com
push dateThu, 14 Jan 2010 19:36:29 +0000
treeherdermozilla-central@6e638c0eedf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs538586
milestone1.9.3a1pre
Test for bug 538586.
ipc/ipdl/test/cxx/Makefile.in
ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
ipc/ipdl/test/cxx/TestCrashCleanup.cpp
ipc/ipdl/test/cxx/TestCrashCleanup.h
ipc/ipdl/test/cxx/TestRPCErrorCleanup.cpp
ipc/ipdl/test/cxx/ipdl.mk
--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -56,16 +56,17 @@ LIBRARY_NAME = $(MODULE)_s
 LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 
 # Please keep these organized in the order "easy"-to-"hard"
 IPDLTESTS = \
   TestSanity  \
   TestRPCErrorCleanup \
+  TestCrashCleanup \
   TestLatency \
   TestRPCRaces \
   TestManyChildAllocs  \
   TestDesc \
   TestShmem \
   TestShutdown \
   TestArrays \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
@@ -0,0 +1,22 @@
+// 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.
+rpc protocol PTestCrashCleanup {
+child:
+    rpc DIEDIEDIE();
+    __delete__();
+
+state ALIVE:
+    call DIEDIEDIE goto CRASH;
+state CRASH:
+    send __delete__;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp
@@ -0,0 +1,116 @@
+#include "TestCrashCleanup.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);
+
+    delete gSubprocess;
+    gSubprocess = NULL;
+
+    cvar->Notify();
+}
+
+void DeleteTheWorld()
+{
+    delete static_cast<TestCrashCleanupParent*>(gParentActor);
+    gParentActor = NULL;
+
+    // needs to be synchronous to avoid affecting event ordering on
+    // the main thread
+    Mutex mutex("TestCrashCleanup.DeleteTheWorld.mutex");
+    CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar");
+
+    MutexAutoLock lock(mutex);
+
+    XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(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 <anon>
+
+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(
+        FROM_HERE, NewRunnableFunction(DeleteTheWorld));
+
+    if (CallDIEDIEDIE())
+        fail("expected an error!");
+
+    Close();
+
+    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done));
+}
+
+
+//-----------------------------------------------------------------------------
+// child
+
+TestCrashCleanupChild::TestCrashCleanupChild()
+{
+    MOZ_COUNT_CTOR(TestCrashCleanupChild);
+}
+
+TestCrashCleanupChild::~TestCrashCleanupChild()
+{
+    MOZ_COUNT_DTOR(TestCrashCleanupChild);
+}
+
+bool
+TestCrashCleanupChild::AnswerDIEDIEDIE()
+{
+    _exit(0);
+    NS_RUNTIMEABORT("unreached");
+    return false;
+}
+
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCrashCleanup.h
@@ -0,0 +1,58 @@
+#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();
+
+    void Main();
+
+protected:    
+    NS_OVERRIDE
+    virtual void ActorDestroy(ActorDestroyReason why)
+    {
+        if (AbnormalShutdown != why)
+            fail("unexpected destruction!");
+        mCleanedUp = true;
+    }
+
+    bool mCleanedUp;
+};
+
+
+class TestCrashCleanupChild :
+    public PTestCrashCleanupChild
+{
+public:
+    TestCrashCleanupChild();
+    virtual ~TestCrashCleanupChild();
+
+protected:
+    NS_OVERRIDE
+    virtual bool AnswerDIEDIEDIE();
+
+    NS_OVERRIDE
+    virtual void ActorDestroy(ActorDestroyReason why)
+    {
+        fail("should have 'crashed'!");
+    }
+};
+
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+
+#endif // ifndef mozilla__ipdltest_TestCrashCleanup_h
--- a/ipc/ipdl/test/cxx/TestRPCErrorCleanup.cpp
+++ b/ipc/ipdl/test/cxx/TestRPCErrorCleanup.cpp
@@ -11,16 +11,18 @@ 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);
 
     delete gSubprocess;
@@ -52,16 +54,18 @@ void Done()
 {
   static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
   nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
   appShell->Exit();
 
   passed(__FILE__);
 }
 
+} // namespace <anon>
+
 TestRPCErrorCleanupParent::TestRPCErrorCleanupParent()
 {
     MOZ_COUNT_CTOR(TestRPCErrorCleanupParent);
 }
 
 TestRPCErrorCleanupParent::~TestRPCErrorCleanupParent()
 {
     MOZ_COUNT_DTOR(TestRPCErrorCleanupParent);
--- a/ipc/ipdl/test/cxx/ipdl.mk
+++ b/ipc/ipdl/test/cxx/ipdl.mk
@@ -1,11 +1,12 @@
 IPDLSRCS =					\
   PTestArrays.ipdl				\
   PTestArraysSub.ipdl				\
+  PTestCrashCleanup.ipdl			\
   PTestDesc.ipdl				\
   PTestDescSub.ipdl				\
   PTestDescSubsub.ipdl				\
   PTestLatency.ipdl				\
   PTestManyChildAllocs.ipdl			\
   PTestManyChildAllocsSub.ipdl			\
   PTestRPCErrorCleanup.ipdl			\
   PTestRPCRaces.ipdl				\