From 8d3f396415457c0b5d3a689f260bc1fcdd98f313 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 11 Mar 2010 01:35:21 -0600 Subject: [PATCH] Bug 545342: Test --- ipc/ipdl/test/cxx/Makefile.in | 1 + ipc/ipdl/test/cxx/PTestRPCShutdownRace.ipdl | 34 +++++ ipc/ipdl/test/cxx/TestRPCShutdownRace.cpp | 140 ++++++++++++++++++++ ipc/ipdl/test/cxx/TestRPCShutdownRace.h | 66 +++++++++ ipc/ipdl/test/cxx/ipdl.mk | 1 + 5 files changed, 242 insertions(+) create mode 100644 ipc/ipdl/test/cxx/PTestRPCShutdownRace.ipdl create mode 100644 ipc/ipdl/test/cxx/TestRPCShutdownRace.cpp create mode 100644 ipc/ipdl/test/cxx/TestRPCShutdownRace.h diff --git a/ipc/ipdl/test/cxx/Makefile.in b/ipc/ipdl/test/cxx/Makefile.in index 6c2a0492499..7ae36895bfb 100644 --- a/ipc/ipdl/test/cxx/Makefile.in +++ b/ipc/ipdl/test/cxx/Makefile.in @@ -66,6 +66,7 @@ IPDLTESTS = \ TestLatency \ TestRPCRaces \ TestRacyRPCReplies \ + TestRPCShutdownRace \ TestHangs \ TestBlockChild \ TestManyChildAllocs \ diff --git a/ipc/ipdl/test/cxx/PTestRPCShutdownRace.ipdl b/ipc/ipdl/test/cxx/PTestRPCShutdownRace.ipdl new file mode 100644 index 00000000000..af49f7a7389 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRPCShutdownRace.ipdl @@ -0,0 +1,34 @@ +namespace mozilla { +namespace _ipdltest { + +rpc protocol PTestRPCShutdownRace { +parent: + sync StartDeath(); + async Orphan(); + +child: + async Start(); + rpc Exit(); + async __delete__(); + +state START: + send Start goto START_DEATH; + +state START_DEATH: + recv StartDeath goto EXITING; + +state EXITING: + recv Orphan goto QUITTING1; + call Exit goto QUITTING2; + +state QUITTING1: + call Exit goto DEAD; +state QUITTING2: + recv Orphan goto DEAD; + +state DEAD: + send __delete__; +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRPCShutdownRace.cpp b/ipc/ipdl/test/cxx/TestRPCShutdownRace.cpp new file mode 100644 index 00000000000..6f92fc1dfa6 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRPCShutdownRace.cpp @@ -0,0 +1,140 @@ +#include "TestRPCShutdownRace.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +template<> +struct RunnableMethodTraits +{ + static void RetainCallee(mozilla::_ipdltest::TestRPCShutdownRaceParent* obj) { } + static void ReleaseCallee(mozilla::_ipdltest::TestRPCShutdownRaceParent* obj) { } +}; + + +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() +{ + delete gSubprocess; + gSubprocess = NULL; +} + +void Done() +{ + passed(__FILE__); + QuitParent(); +} + +} // namespace + +TestRPCShutdownRaceParent::TestRPCShutdownRaceParent() +{ + MOZ_COUNT_CTOR(TestRPCShutdownRaceParent); +} + +TestRPCShutdownRaceParent::~TestRPCShutdownRaceParent() +{ + MOZ_COUNT_DTOR(TestRPCShutdownRaceParent); +} + +void +TestRPCShutdownRaceParent::Main() +{ + if (!SendStart()) + fail("sending Start"); +} + +bool +TestRPCShutdownRaceParent::RecvStartDeath() +{ + // this will be ordered before the OnMaybeDequeueOne event of + // Orphan in the queue + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &TestRPCShutdownRaceParent::StartShuttingDown)); + return true; +} + +void +TestRPCShutdownRaceParent::StartShuttingDown() +{ + // NB: we sleep here to try and avoid receiving the Orphan message + // while waiting for the CallExit() reply. if we fail at that, it + // will cause the test to pass spuriously, because there won't be + // an OnMaybeDequeueOne task for Orphan + PR_Sleep(2000); + + if (CallExit()) + fail("connection was supposed to be interrupted"); + + Close(); + + delete static_cast(gParentActor); + gParentActor = NULL; + + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, + NewRunnableFunction(DeleteSubprocess)); + + // this is ordered after the OnMaybeDequeueOne event in the queue + MessageLoop::current()->PostTask(FROM_HERE, + NewRunnableFunction(Done)); + + // |this| has been deleted, be mindful +} + +bool +TestRPCShutdownRaceParent::RecvOrphan() +{ + // it would be nice to fail() here, but we'll process this message + // while waiting for the reply CallExit(). The OnMaybeDequeueOne + // task will still be in the queue, it just wouldn't have had any + // work to do, if we hadn't deleted ourself + return true; +} + +//----------------------------------------------------------------------------- +// child + +TestRPCShutdownRaceChild::TestRPCShutdownRaceChild() +{ + MOZ_COUNT_CTOR(TestRPCShutdownRaceChild); +} + +TestRPCShutdownRaceChild::~TestRPCShutdownRaceChild() +{ + MOZ_COUNT_DTOR(TestRPCShutdownRaceChild); +} + +bool +TestRPCShutdownRaceChild::RecvStart() +{ + if (!SendStartDeath()) + fail("sending StartDeath"); + + if (!SendOrphan()) + fail("sending Orphan"); + + return true; +} + +bool +TestRPCShutdownRaceChild::AnswerExit() +{ + _exit(0); + NS_RUNTIMEABORT("unreached"); + return false; +} + + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRPCShutdownRace.h b/ipc/ipdl/test/cxx/TestRPCShutdownRace.h new file mode 100644 index 00000000000..3c1acc730d9 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRPCShutdownRace.h @@ -0,0 +1,66 @@ +#ifndef mozilla__ipdltest_TestRPCShutdownRace_h +#define mozilla__ipdltest_TestRPCShutdownRace_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRPCShutdownRaceParent.h" +#include "mozilla/_ipdltest/PTestRPCShutdownRaceChild.h" + +namespace mozilla { +namespace _ipdltest { + + +class TestRPCShutdownRaceParent : + public PTestRPCShutdownRaceParent +{ +public: + TestRPCShutdownRaceParent(); + virtual ~TestRPCShutdownRaceParent(); + + void Main(); + + NS_OVERRIDE + virtual bool RecvStartDeath(); + + NS_OVERRIDE + virtual bool RecvOrphan(); + +protected: + void StartShuttingDown(); + + NS_OVERRIDE + virtual void ActorDestroy(ActorDestroyReason why) + { + if (AbnormalShutdown != why) + fail("unexpected destruction!"); + } +}; + + +class TestRPCShutdownRaceChild : + public PTestRPCShutdownRaceChild +{ +public: + TestRPCShutdownRaceChild(); + virtual ~TestRPCShutdownRaceChild(); + +protected: + NS_OVERRIDE + virtual bool RecvStart(); + + NS_OVERRIDE + virtual bool AnswerExit(); + + NS_OVERRIDE + virtual void ActorDestroy(ActorDestroyReason why) + { + fail("should have 'crashed'!"); + } +}; + + +} // namespace _ipdltest +} // namespace mozilla + + +#endif // ifndef mozilla__ipdltest_TestRPCShutdownRace_h diff --git a/ipc/ipdl/test/cxx/ipdl.mk b/ipc/ipdl/test/cxx/ipdl.mk index 16babce65fb..41062d9036a 100644 --- a/ipc/ipdl/test/cxx/ipdl.mk +++ b/ipc/ipdl/test/cxx/ipdl.mk @@ -17,6 +17,7 @@ IPDLSRCS = \ PTestRacyRPCReplies.ipdl \ PTestRPCErrorCleanup.ipdl \ PTestRPCRaces.ipdl \ + PTestRPCShutdownRace.ipdl \ PTestSanity.ipdl \ PTestShmem.ipdl \ PTestShutdown.ipdl \