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 179486 2c59614ef6d351e08a9483685ccdcf67f139f95b
parent 179485 5d5dae8097ef84b87e3f4214b70108bf5f81c94f
child 179487 12d543cfa1677371da8753fd847c5cc5d07433b3
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbsmedberg
bugs997286
milestone31.0a1
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;