Bug 1237414: Switch AsyncCubebOperation to a SharedThreadPool draft
authorRandell Jesup <rjesup@jesup.org>
Tue, 12 Jan 2016 18:14:14 -0500
changeset 321203 0976334fd451924c7f0c04579239b7b7e64e7096
parent 321202 e83fa940db034828fa79612c6b9f3c9371883f6d
child 321204 ffe4d752ee669b0efdfae105bacdd51e6bd1e697
push id9349
push userrjesup@wgate.com
push dateWed, 13 Jan 2016 06:48:48 +0000
bugs1237414
milestone46.0a1
Bug 1237414: Switch AsyncCubebOperation to a SharedThreadPool
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,46 @@ 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;
+    if (!NS_IsMainThread()) {
+      NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
+        ClearOnShutdown(&sThreadPool);
+      }));
+    } else {
+      ClearOnShutdown(&sThreadPool);
+    }
+
+    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 +521,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_