michael@0: #include "TestInterruptShutdownRace.h" michael@0: michael@0: #include "IPDLUnitTests.h" // fail etc. michael@0: #include "IPDLUnitTestSubprocess.h" michael@0: michael@0: template<> michael@0: struct RunnableMethodTraits michael@0: { michael@0: static void RetainCallee(mozilla::_ipdltest::TestInterruptShutdownRaceParent* obj) { } michael@0: static void ReleaseCallee(mozilla::_ipdltest::TestInterruptShutdownRaceParent* obj) { } michael@0: }; michael@0: michael@0: michael@0: namespace mozilla { michael@0: namespace _ipdltest { michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // parent michael@0: michael@0: namespace { michael@0: michael@0: // NB: this test does its own shutdown, rather than going through michael@0: // QuitParent(), because it's testing degenerate edge cases michael@0: michael@0: void DeleteSubprocess() michael@0: { michael@0: delete gSubprocess; michael@0: gSubprocess = nullptr; michael@0: } michael@0: michael@0: void Done() michael@0: { michael@0: passed(__FILE__); michael@0: QuitParent(); michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent() michael@0: { michael@0: MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent); michael@0: } michael@0: michael@0: TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent() michael@0: { michael@0: MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent); michael@0: } michael@0: michael@0: void michael@0: TestInterruptShutdownRaceParent::Main() michael@0: { michael@0: if (!SendStart()) michael@0: fail("sending Start"); michael@0: } michael@0: michael@0: bool michael@0: TestInterruptShutdownRaceParent::RecvStartDeath() michael@0: { michael@0: // this will be ordered before the OnMaybeDequeueOne event of michael@0: // Orphan in the queue michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, michael@0: &TestInterruptShutdownRaceParent::StartShuttingDown)); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TestInterruptShutdownRaceParent::StartShuttingDown() michael@0: { michael@0: // NB: we sleep here to try and avoid receiving the Orphan message michael@0: // while waiting for the CallExit() reply. if we fail at that, it michael@0: // will cause the test to pass spuriously, because there won't be michael@0: // an OnMaybeDequeueOne task for Orphan michael@0: PR_Sleep(2000); michael@0: michael@0: if (CallExit()) michael@0: fail("connection was supposed to be interrupted"); michael@0: michael@0: Close(); michael@0: michael@0: delete static_cast(gParentActor); michael@0: gParentActor = nullptr; michael@0: michael@0: XRE_GetIOMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(DeleteSubprocess)); michael@0: michael@0: // this is ordered after the OnMaybeDequeueOne event in the queue michael@0: MessageLoop::current()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(Done)); michael@0: michael@0: // |this| has been deleted, be mindful michael@0: } michael@0: michael@0: bool michael@0: TestInterruptShutdownRaceParent::RecvOrphan() michael@0: { michael@0: // it would be nice to fail() here, but we'll process this message michael@0: // while waiting for the reply CallExit(). The OnMaybeDequeueOne michael@0: // task will still be in the queue, it just wouldn't have had any michael@0: // work to do, if we hadn't deleted ourself michael@0: return true; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // child michael@0: michael@0: TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild() michael@0: { michael@0: MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild); michael@0: } michael@0: michael@0: TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild() michael@0: { michael@0: MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild); michael@0: } michael@0: michael@0: bool michael@0: TestInterruptShutdownRaceChild::RecvStart() michael@0: { michael@0: if (!SendStartDeath()) michael@0: fail("sending StartDeath"); michael@0: michael@0: // See comment in StartShuttingDown(): we want to send Orphan() michael@0: // while the parent is in its PR_Sleep() michael@0: PR_Sleep(1000); michael@0: michael@0: if (!SendOrphan()) michael@0: fail("sending Orphan"); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TestInterruptShutdownRaceChild::AnswerExit() michael@0: { michael@0: _exit(0); michael@0: NS_RUNTIMEABORT("unreached"); michael@0: return false; michael@0: } michael@0: michael@0: michael@0: } // namespace _ipdltest michael@0: } // namespace mozilla