Bug 968016 - Add a parameter to SharedThreadPool to control the number of threads in the pool. r=kinteik
authorChris Pearce <cpearce@mozilla.com>
Tue, 18 Feb 2014 11:53:52 +1300
changeset 169507 406b7fde02e24c786ebe70f6019a88a7e30b3ef9
parent 169506 0f78e7bb808cd11027647b99c8ab428ad67549d3
child 169508 d71ac8b9f7ded0261113a9e078d39a296e23d33b
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskinteik
bugs968016
milestone30.0a1
Bug 968016 - Add a parameter to SharedThreadPool to control the number of threads in the pool. r=kinteik
content/media/SharedThreadPool.cpp
content/media/SharedThreadPool.h
content/media/wmf/WMFByteStream.cpp
--- a/content/media/SharedThreadPool.cpp
+++ b/content/media/SharedThreadPool.cpp
@@ -6,17 +6,16 @@
 
 #include "SharedThreadPool.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPtr.h"
 #include "nsDataHashtable.h"
 #include "VideoUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
-#include "mozilla/Preferences.h"
 
 #ifdef XP_WIN
 // Required to init MSCOM by MSCOMInitThreadPoolListener.
 #include <objbase.h>
 #endif
 
 namespace mozilla {
 
@@ -65,29 +64,45 @@ DestroySharedThreadPoolHashTable()
     // hash table on the main thread, and if the hash table is empty
     // there are no external references into its contents.
     sPools = nullptr;
     sMonitor = nullptr;
   }
 }
 
 TemporaryRef<SharedThreadPool>
-SharedThreadPool::Get(const nsCString& aName)
+SharedThreadPool::Get(const nsCString& aName, uint32_t aThreadLimit)
 {
   MOZ_ASSERT(NS_IsMainThread());
   EnsureInitialized();
   MOZ_ASSERT(sMonitor);
   ReentrantMonitorAutoEnter mon(*sMonitor);
   SharedThreadPool* pool = nullptr;
+  nsresult rv;
   if (!sPools->Get(aName, &pool)) {
     nsCOMPtr<nsIThreadPool> threadPool(CreateThreadPool(aName));
     NS_ENSURE_TRUE(threadPool, nullptr);
     pool = new SharedThreadPool(aName, threadPool);
+
+    // Set the thread and idle limits. Note that we don't rely on the
+    // EnsureThreadLimitIsAtLeast() call below, as the default thread limit
+    // is 4, and if aThreadLimit is less than 4 we'll end up with a pool
+    // with 4 threads rather than what we expected; so we'll have unexpected
+    // behaviour.
+    rv = pool->SetThreadLimit(aThreadLimit);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    rv = pool->SetIdleThreadLimit(aThreadLimit);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
     sPools->Put(aName, pool);
+  } else if (NS_FAILED(pool->EnsureThreadLimitIsAtLeast(aThreadLimit))) {
+    NS_WARNING("Failed to set limits on thread pool");
   }
+
   MOZ_ASSERT(pool);
   RefPtr<SharedThreadPool> instance(pool);
   return instance.forget();
 }
 
 NS_IMETHODIMP_(nsrefcnt) SharedThreadPool::AddRef(void)
 {
   MOZ_ASSERT(sMonitor);
@@ -182,43 +197,58 @@ NS_IMETHODIMP
 MSCOMInitThreadPoolListener::OnThreadShuttingDown()
 {
   CoUninitialize();
   return NS_OK;
 }
 
 #endif // XP_WIN
 
+nsresult
+SharedThreadPool::EnsureThreadLimitIsAtLeast(uint32_t aLimit)
+{
+  // We limit the number of threads that we use for media. Note that we
+  // set the thread limit to the same as the idle limit so that we're not
+  // constantly creating and destroying threads (see Bug 881954). When the
+  // thread pool threads shutdown they dispatch an event to the main thread
+  // to call nsIThread::Shutdown(), and if we're very busy that can take a
+  // while to run, and we end up with dozens of extra threads. Note that
+  // threads that are idle for 60 seconds are shutdown naturally.
+  uint32_t existingLimit = 0;
+  nsresult rv;
+
+  rv = mPool->GetThreadLimit(&existingLimit);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (aLimit > existingLimit) {
+    rv = mPool->SetThreadLimit(aLimit);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = mPool->GetIdleThreadLimit(&existingLimit);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (aLimit > existingLimit) {
+    rv = mPool->SetIdleThreadLimit(aLimit);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
 static already_AddRefed<nsIThreadPool>
 CreateThreadPool(const nsCString& aName)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
   nsCOMPtr<nsIThreadPool> pool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   rv = pool->SetName(aName);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
-  // We limit the number of threads that we use for media. Note that the
-  // default thread limit is the same as the idle limit so that we're not
-  // constantly creating and destroying threads (see Bug 881954). When the
-  // thread pool threads shutdown they dispatch an event to the main thread
-  // to call nsIThread::Shutdown(), and if we're very busy that can take a
-  // while to run, and we end up with dozens of extra threads. Note that
-  // threads that are idle for 60 seconds are shutdown naturally.
-  rv = pool->SetThreadLimit(
-    Preferences::GetUint("media.thread-pool.thread-limit", 4));
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  rv = pool->SetIdleThreadLimit(
-    Preferences::GetUint("media.thread-pool.idle-thread-limit", 4));
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
 #ifdef XP_WIN
   // Ensure MSCOM is initialized on the thread pools threads.
   nsCOMPtr<nsIThreadPoolListener> listener = new MSCOMInitThreadPoolListener();
   rv = pool->SetListener(listener);
   NS_ENSURE_SUCCESS(rv, nullptr);
 #endif
 
   return pool.forget();
--- a/content/media/SharedThreadPool.h
+++ b/content/media/SharedThreadPool.h
@@ -26,17 +26,18 @@ namespace mozilla {
 // shutdown the pool, and can release references on any thread. On Windows
 // all threads in the pool have MSCOM initialized with COINIT_MULTITHREADED.
 class SharedThreadPool : public nsIThreadPool {
 public:
 
   // Gets (possibly creating) the shared thread pool singleton instance with
   // thread pool named aName.
   // *Must* be called on the main thread.
-  static TemporaryRef<SharedThreadPool> Get(const nsCString& aName);
+  static TemporaryRef<SharedThreadPool> Get(const nsCString& aName,
+                                            uint32_t aThreadLimit = 4);
 
   // We implement custom threadsafe AddRef/Release pair, that destroys the
   // the shared pool singleton when the refcount drops to 0. The addref/release
   // are implemented using locking, so it's not recommended that you use them
   // in a tight loop.
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
   NS_IMETHOD_(nsrefcnt) AddRef(void);
   NS_IMETHOD_(nsrefcnt) Release(void);
@@ -49,19 +50,22 @@ private:
 
   // Creates necessary statics.
   // Main thread only.
   static void EnsureInitialized();
 
   // Creates a singleton SharedThreadPool wrapper around aPool.
   // aName is the name of the aPool, and is used to lookup the
   // SharedThreadPool in the hash table of all created pools.
-  SharedThreadPool(const nsCString& aName, nsIThreadPool* aPool);
+  SharedThreadPool(const nsCString& aName,
+                   nsIThreadPool* aPool);
   virtual ~SharedThreadPool();
 
+  nsresult EnsureThreadLimitIsAtLeast(uint32_t aThreadLimit);
+
   // Name of mPool.
   const nsCString mName;
 
   // Thread pool being wrapped.
   nsCOMPtr<nsIThreadPool> mPool;
 
   // Refcount. We implement custom ref counting so that the thread pool is
   // shutdown in a threadsafe manner and singletonness is preserved.
--- a/content/media/wmf/WMFByteStream.cpp
+++ b/content/media/wmf/WMFByteStream.cpp
@@ -58,17 +58,17 @@ WMFByteStream::~WMFByteStream()
   WMF_BS_LOG("[%p] WMFByteStream DTOR", this);
 }
 
 nsresult
 WMFByteStream::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
 
-  mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"));
+  mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4);
   NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE);
 
   NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType());
   if (!contentTypeUTF16.IsEmpty()) {
     HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
     NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
     hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,