Bug 997286: Don't depend on NewThread event timing; add test for suicidal initial events r=bsmedberg
authorRandell Jesup <rjesup@jesup.org>
Thu, 17 Apr 2014 15:13:44 -0400
changeset 179170 2c59614ef6d351e08a9483685ccdcf67f139f95b
parent 179169 5d5dae8097ef84b87e3f4214b70108bf5f81c94f
child 179171 12d543cfa1677371da8753fd847c5cc5d07433b3
push id26607
push userryanvm@gmail.com
push dateFri, 18 Apr 2014 02:31:26 +0000
treeherdermozilla-central@7fe3ee0cf8be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs997286
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 997286: Don't depend on NewThread event timing; add test for suicidal initial events r=bsmedberg
content/media/AudioStream.cpp
content/media/AudioStream.h
xpcom/tests/TestThreadUtils.cpp
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -497,16 +497,17 @@ AudioStream::CheckForStart()
               mLatencyRequest == LowLatency ? "low" : "high"));
     }
   }
 }
 
 NS_IMETHODIMP
 AudioInitTask::Run()
 {
+  MOZ_ASSERT(mThread);
   if (NS_IsMainThread()) {
     mThread->Shutdown(); // can't Shutdown from the thread itself, darn
     mThread = nullptr;
     return NS_OK;
   }
 
   nsresult rv = mAudioStream->OpenCubeb(mParams, mLatencyRequest);
 
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -428,17 +428,22 @@ public:
                 const cubeb_stream_params &aParams)
     : mAudioStream(aStream)
     , mLatencyRequest(aLatencyRequest)
     , mParams(aParams)
   {}
 
   nsresult Dispatch()
   {
-    return NS_NewNamedThread("CubebInit", getter_AddRefs(mThread), this);
+    // Can't add 'this' as the event to run, since mThread may not be set yet
+    nsresult rv = NS_NewNamedThread("CubebInit", getter_AddRefs(mThread));
+    if (NS_SUCCEEDED(rv)) {
+      rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
+    }
+    return rv;
   }
 
 protected:
   virtual ~AudioInitTask() {};
 
 private:
   NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL;
 
--- a/xpcom/tests/TestThreadUtils.cpp
+++ b/xpcom/tests/TestThreadUtils.cpp
@@ -14,32 +14,51 @@ enum {
   TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
 #ifdef HAVE_STDCALL
   TEST_STDCALL_VOID_ARG_VOID_RETURN,
   TEST_STDCALL_VOID_ARG_NONVOID_RETURN,
   TEST_STDCALL_NONVOID_ARG_VOID_RETURN,
   TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN,
   TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
 #endif
+  TEST_CALL_NEWTHREAD_SUICIDAL,
   MAX_TESTS
 };
 
 bool gRunnableExecuted[MAX_TESTS];
 
 class nsFoo : public nsISupports {
   NS_DECL_ISUPPORTS
   nsresult DoFoo(bool* aBool) {
     *aBool = true;
     return NS_OK;
   }
   virtual ~nsFoo() {}
 };
 
 NS_IMPL_ISUPPORTS0(nsFoo)
 
+class TestSuicide : public nsRunnable {
+  nsresult Run() {
+    // Runs first time on thread "Suicide", then dies on MainThread
+    if (!NS_IsMainThread()) {
+      mThread = do_GetCurrentThread();
+      NS_DispatchToMainThread(this);
+      return NS_OK;
+    }
+    MOZ_ASSERT(mThread);
+    mThread->Shutdown();
+    gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true;
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIThread> mThread;
+};
+
 class nsBar : public nsISupports {
   NS_DECL_ISUPPORTS
   virtual ~nsBar() {}
   void DoBar1(void) {
     gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true;
   }
   nsresult DoBar2(void) {
     gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true;
@@ -126,16 +145,25 @@ int main(int argc, char** argv)
 #endif
 
     delete rawFoo;
   }
 
   // Spin the event loop
   NS_ProcessPendingEvents(nullptr);
 
+  // Now test a suicidal event in NS_New(Named)Thread
+  nsCOMPtr<nsIThread> thread;
+  NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide());
+  MOZ_ASSERT(thread);
+
+  while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) {
+    NS_ProcessPendingEvents(nullptr);
+  }
+
   int result = 0;
 
   for (uint32_t i = 0; i < MAX_TESTS; i++) {
     if (gRunnableExecuted[i]) {
       passed("Test %d passed",i);
     } else {
       fail("Error in test %d", i);
       result = 1;