Bug 1237414: Switch AsyncCubebOperation to a SharedThreadPool r=padenot
authorRandell Jesup <rjesup@jesup.org>
Thu, 21 Jan 2016 11:51:36 -0500
changeset 281174 7da3fd66093c460ad20b7d53b00d33ec29e307dc
parent 281173 86eee3f50995d5df4260bc9115369df94e7db121
child 281175 e97c3cf176607e044ebd1c9d24de52ae5b796e48
push id29930
push usercbook@mozilla.com
push dateFri, 22 Jan 2016 11:05:50 +0000
treeherdermozilla-central@7104d650a97d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1237414
milestone46.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 1237414: Switch AsyncCubebOperation to a SharedThreadPool r=padenot
dom/media/GraphDriver.cpp
dom/media/GraphDriver.h
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <MediaStreamGraphImpl.h>
 #include "mozilla/dom/AudioContext.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/ClearOnShutdown.h"
 #include "CubebUtils.h"
 
 #ifdef XP_MACOSX
 #include <sys/sysctl.h>
 #endif
 
 extern mozilla::LazyLogModule gMediaStreamGraphLog;
 #define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
@@ -25,16 +27,18 @@ extern mozilla::LazyLogModule gMediaStre
 #define LIFECYCLE_LOG(...) printf(__VA_ARGS__);printf("\n");
 #endif
 #else
 #define LIFECYCLE_LOG(...)
 #endif
 
 namespace mozilla {
 
+StaticRefPtr<nsIThreadPool> AsyncCubebTask::sThreadPool;
+
 struct AutoProfilerUnregisterThread
 {
   // The empty ctor is used to silence a pre-4.8.0 GCC unused variable warning.
   AutoProfilerUnregisterThread()
   {
   }
 
   ~AutoProfilerUnregisterThread()
@@ -464,30 +468,49 @@ AsyncCubebTask::AsyncCubebTask(AudioCall
 {
   NS_WARN_IF_FALSE(mDriver->mAudioStream || aOperation == INIT, "No audio stream !");
 }
 
 AsyncCubebTask::~AsyncCubebTask()
 {
 }
 
+/* static */
+nsresult
+AsyncCubebTask::EnsureThread()
+{
+  if (!sThreadPool) {
+    nsCOMPtr<nsIThreadPool> threadPool =
+      SharedThreadPool::Get(NS_LITERAL_CSTRING("CubebOperation"), 1);
+    sThreadPool = threadPool;
+    // Need to null this out before xpcom-shutdown-threads Observers run
+    // since we don't know the order that the shutdown-threads observers
+    // will run.  ClearOnShutdown guarantees it runs first.
+    if (!NS_IsMainThread()) {
+      NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
+            ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
+      }));
+    } else {
+      ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
+    }
+
+    const uint32_t kIdleThreadTimeoutMs = 2000;
+
+    nsresult rv = sThreadPool->SetIdleThreadTimeout(PR_MillisecondsToInterval(kIdleThreadTimeoutMs));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 AsyncCubebTask::Run()
 {
-  MOZ_ASSERT(mThread);
-  if (NS_IsMainThread()) {
-    mThread->Shutdown(); // can't shutdown from the thread itself, darn
-    // don't null out mThread!
-    // See bug 999104.  we must hold a ref to the thread across Dispatch()
-    // since the internal mthread ref could be released while processing
-    // the Dispatch(), and Dispatch/PutEvent itself doesn't hold a ref; it
-    // assumes the caller does.
-    return NS_OK;
-  }
-
   MOZ_ASSERT(mDriver);
 
   switch(mOperation) {
     case AsyncCubebOperation::INIT: {
       LIFECYCLE_LOG("AsyncCubebOperation::INIT driver=%p\n", mDriver.get());
       mDriver->Init();
       mDriver->CompleteAudioContextOperations(mOperation);
       break;
@@ -501,19 +524,17 @@ AsyncCubebTask::Run()
       mDriver = nullptr;
       mShutdownGrip = nullptr;
       break;
     }
     default:
       MOZ_CRASH("Operation not implemented.");
   }
 
-  // and now kill this thread
-  NS_DispatchToMainThread(this);
-
+  // The thread will kill itself after a bit
   return NS_OK;
 }
 
 StreamAndPromiseForOperation::StreamAndPromiseForOperation(MediaStream* aStream,
                                           void* aPromise,
                                           dom::AudioContextOperation aOperation)
   : mStream(aStream)
   , mPromise(aPromise)
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -8,16 +8,18 @@
 
 #include "nsAutoPtr.h"
 #include "nsAutoRef.h"
 #include "AudioBufferUtils.h"
 #include "AudioMixer.h"
 #include "AudioSegment.h"
 #include "SelfRef.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/StaticPtr.h"
 
 struct cubeb_stream;
 
 template <>
 class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
 {
 public:
   static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
@@ -544,31 +546,31 @@ private:
 class AsyncCubebTask : public nsRunnable
 {
 public:
 
   AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation);
 
   nsresult Dispatch()
   {
-    // Can't add 'this' as the event to run, since mThread may not be set yet
-    nsresult rv = NS_NewNamedThread("CubebOperation", getter_AddRefs(mThread));
-    if (NS_SUCCEEDED(rv)) {
-      // Note: event must not null out mThread!
-      rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
+    nsresult rv = EnsureThread();
+    if (!NS_FAILED(rv)) {
+      rv = sThreadPool->Dispatch(this, NS_DISPATCH_NORMAL);
     }
     return rv;
   }
 
 protected:
   virtual ~AsyncCubebTask();
 
 private:
+  static nsresult EnsureThread();
+
   NS_IMETHOD Run() override final;
-  nsCOMPtr<nsIThread> mThread;
+  static StaticRefPtr<nsIThreadPool> sThreadPool;
   RefPtr<AudioCallbackDriver> mDriver;
   AsyncCubebOperation mOperation;
   RefPtr<MediaStreamGraphImpl> mShutdownGrip;
 };
 
 } // namespace mozilla
 
 #endif // GRAPHDRIVER_H_