michael@0: #include "TestCrashCleanup.h" michael@0: michael@0: #include "mozilla/CondVar.h" michael@0: #include "mozilla/Mutex.h" michael@0: michael@0: #include "IPDLUnitTests.h" // fail etc. michael@0: #include "IPDLUnitTestSubprocess.h" michael@0: michael@0: using mozilla::CondVar; michael@0: using mozilla::Mutex; michael@0: using mozilla::MutexAutoLock; 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(Mutex* mutex, CondVar* cvar) michael@0: { michael@0: MutexAutoLock lock(*mutex); michael@0: michael@0: delete gSubprocess; michael@0: gSubprocess = nullptr; michael@0: michael@0: cvar->Notify(); michael@0: } michael@0: michael@0: void DeleteTheWorld() michael@0: { michael@0: delete static_cast(gParentActor); michael@0: gParentActor = nullptr; michael@0: michael@0: // needs to be synchronous to avoid affecting event ordering on michael@0: // the main thread michael@0: Mutex mutex("TestCrashCleanup.DeleteTheWorld.mutex"); michael@0: CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar"); michael@0: michael@0: MutexAutoLock lock(mutex); michael@0: michael@0: XRE_GetIOMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(DeleteSubprocess, &mutex, &cvar)); michael@0: michael@0: cvar.Wait(); michael@0: } michael@0: michael@0: void Done() michael@0: { michael@0: static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); michael@0: nsCOMPtr appShell (do_GetService(kAppShellCID)); michael@0: appShell->Exit(); michael@0: michael@0: passed(__FILE__); michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false) michael@0: { michael@0: MOZ_COUNT_CTOR(TestCrashCleanupParent); michael@0: } michael@0: michael@0: TestCrashCleanupParent::~TestCrashCleanupParent() michael@0: { michael@0: MOZ_COUNT_DTOR(TestCrashCleanupParent); michael@0: michael@0: if (!mCleanedUp) michael@0: fail("should have been ActorDestroy()d!"); michael@0: } michael@0: michael@0: void michael@0: TestCrashCleanupParent::Main() michael@0: { michael@0: // NB: has to be enqueued before IO thread's error notification michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, NewRunnableFunction(DeleteTheWorld)); michael@0: michael@0: if (CallDIEDIEDIE()) michael@0: fail("expected an error!"); michael@0: michael@0: Close(); michael@0: michael@0: MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done)); michael@0: } michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // child michael@0: michael@0: TestCrashCleanupChild::TestCrashCleanupChild() michael@0: { michael@0: MOZ_COUNT_CTOR(TestCrashCleanupChild); michael@0: } michael@0: michael@0: TestCrashCleanupChild::~TestCrashCleanupChild() michael@0: { michael@0: MOZ_COUNT_DTOR(TestCrashCleanupChild); michael@0: } michael@0: michael@0: bool michael@0: TestCrashCleanupChild::AnswerDIEDIEDIE() 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