Bug 1119158 - Retarget OnDataAvailable to a new I/O thread instead of the image decoding thread pool. r=sworkman
☠☠ backed out by 7967b585efe9 ☠ ☠
authorSeth Fowler <seth@mozilla.com>
Mon, 12 Jan 2015 01:29:25 -0800
changeset 249148 a15929ba55cdbbb56f9c8b23c71d09c5db410266
parent 249147 0b1b75d692bfbd52a5300e9f1beaf0df5155dfb8
child 249149 c37e10cff7654d9a8b0f8af8571c3f40bcef72b3
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssworkman
bugs1119158
milestone37.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 1119158 - Retarget OnDataAvailable to a new I/O thread instead of the image decoding thread pool. r=sworkman
image/src/DecodePool.cpp
image/src/DecodePool.h
image/src/imgRequest.cpp
--- a/image/src/DecodePool.cpp
+++ b/image/src/DecodePool.cpp
@@ -7,16 +7,17 @@
 
 #include <algorithm>
 
 #include "mozilla/ClearOnShutdown.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIObserverService.h"
 #include "nsIThreadPool.h"
+#include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "prsystem.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 #include "gfxPrefs.h"
@@ -175,17 +176,17 @@ DecodePool::Singleton()
     sSingleton = new DecodePool();
     ClearOnShutdown(&sSingleton);
   }
 
   return sSingleton;
 }
 
 DecodePool::DecodePool()
-  : mThreadPoolMutex("Thread Pool")
+  : mMutex("image::DecodePool")
 {
   mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
   MOZ_RELEASE_ASSERT(mThreadPool,
                      "Should succeed in creating image decoding thread pool");
 
   mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
   int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit();
   uint32_t limit;
@@ -199,16 +200,21 @@ DecodePool::DecodePool()
   mThreadPool->SetIdleThreadLimit(limit);
 
 #ifdef MOZ_NUWA_PROCESS
   if (IsNuwaProcess()) {
     mThreadPool->SetListener(new RIDThreadPoolListener());
   }
 #endif
 
+  // Initialize the I/O thread.
+  nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread));
+  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOThread,
+                     "Should successfully create image I/O thread");
+
   nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
   if (obsSvc) {
     obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
   }
 }
 
 DecodePool::~DecodePool()
 {
@@ -216,40 +222,45 @@ DecodePool::~DecodePool()
 }
 
 NS_IMETHODIMP
 DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*)
 {
   MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
 
   nsCOMPtr<nsIThreadPool> threadPool;
+  nsCOMPtr<nsIThread> ioThread;
 
   {
-    MutexAutoLock threadPoolLock(mThreadPoolMutex);
-    threadPool = mThreadPool;
-    mThreadPool = nullptr;
+    MutexAutoLock lock(mMutex);
+    threadPool.swap(mThreadPool);
+    ioThread.swap(mIOThread);
   }
 
   if (threadPool) {
     threadPool->Shutdown();
   }
 
+  if (ioThread) {
+    ioThread->Shutdown();
+  }
+
   return NS_OK;
 }
 
 void
 DecodePool::AsyncDecode(Decoder* aDecoder)
 {
   MOZ_ASSERT(aDecoder);
 
   nsCOMPtr<nsIRunnable> worker = new DecodeWorker(aDecoder);
 
   // Dispatch to the thread pool if it exists. If it doesn't, we're currently
   // shutting down, so it's OK to just drop the job on the floor.
-  MutexAutoLock threadPoolLock(mThreadPoolMutex);
+  MutexAutoLock threadPoolLock(mMutex);
   if (mThreadPool) {
     mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL);
   }
 }
 
 void
 DecodePool::SyncDecodeIfSmall(Decoder* aDecoder)
 {
@@ -269,21 +280,29 @@ DecodePool::SyncDecodeIfPossible(Decoder
 {
   MOZ_ASSERT(NS_IsMainThread());
   Decode(aDecoder);
 }
 
 already_AddRefed<nsIEventTarget>
 DecodePool::GetEventTarget()
 {
-  MutexAutoLock threadPoolLock(mThreadPoolMutex);
+  MutexAutoLock threadPoolLock(mMutex);
   nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
   return target.forget();
 }
 
+already_AddRefed<nsIEventTarget>
+DecodePool::GetIOEventTarget()
+{
+  MutexAutoLock threadPoolLock(mMutex);
+  nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mIOThread);
+  return target.forget();
+}
+
 already_AddRefed<nsIRunnable>
 DecodePool::CreateDecodeWorker(Decoder* aDecoder)
 {
   MOZ_ASSERT(aDecoder);
   nsCOMPtr<nsIRunnable> worker = new DecodeWorker(aDecoder);
   return worker.forget();
 }
 
--- a/image/src/DecodePool.h
+++ b/image/src/DecodePool.h
@@ -12,16 +12,17 @@
 
 #include "mozilla/Mutex.h"
 #include "mozilla/StaticPtr.h"
 #include <mozilla/TypedEnum.h>
 #include "nsCOMPtr.h"
 #include "nsIEventTarget.h"
 #include "nsIObserver.h"
 
+class nsIThread;
 class nsIThreadPool;
 
 namespace mozilla {
 namespace image {
 
 class Decoder;
 class RasterImage;
 
@@ -65,16 +66,25 @@ public:
    * pool. Callers can use this event target to submit work to the image
    * decoding thread pool.
    *
    * @return An nsIEventTarget interface to the thread pool.
    */
   already_AddRefed<nsIEventTarget> GetEventTarget();
 
   /**
+   * Returns an event target interface to the DecodePool's I/O thread. Callers
+   * who want to deliver data to workers on the DecodePool can use this event
+   * target.
+   *
+   * @return An nsIEventTarget interface to the thread pool's I/O thread.
+   */
+  already_AddRefed<nsIEventTarget> GetIOEventTarget();
+
+  /**
    * Creates a worker which can be used to attempt further decoding using the
    * provided decoder.
    *
    * @return The new worker, which should be posted to the event target returned
    *         by GetEventTarget.
    */
   already_AddRefed<nsIRunnable> CreateDecodeWorker(Decoder* aDecoder);
 
@@ -86,19 +96,18 @@ private:
   virtual ~DecodePool();
 
   void Decode(Decoder* aDecoder);
   void NotifyDecodeComplete(Decoder* aDecoder);
   void NotifyProgress(Decoder* aDecoder);
 
   static StaticRefPtr<DecodePool> sSingleton;
 
-  // mThreadPoolMutex protects mThreadPool. For all RasterImages R,
-  // R::mDecodingMonitor must be acquired before mThreadPoolMutex
-  // if both are acquired; the other order may cause deadlock.
-  Mutex                     mThreadPoolMutex;
+  // mMutex protects mThreadPool and mIOThread.
+  Mutex                     mMutex;
   nsCOMPtr<nsIThreadPool>   mThreadPool;
+  nsCOMPtr<nsIThread>       mIOThread;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // MOZILLA_IMAGELIB_DECODEPOOL_H_
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -694,20 +694,19 @@ NS_IMETHODIMP imgRequest::OnStartRequest
   // Try to retarget OnDataAvailable to a decode thread.
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
     do_QueryInterface(aRequest);
   if (httpChannel && retargetable) {
     nsAutoCString mimeType;
     nsresult rv = httpChannel->GetContentType(mimeType);
     if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
-      // Image object not created until OnDataAvailable, so forward to static
-      // DecodePool directly.
+      // Retarget OnDataAvailable to the DecodePool's IO thread.
       nsCOMPtr<nsIEventTarget> target =
-        DecodePool::Singleton()->GetEventTarget();
+        DecodePool::Singleton()->GetIOEventTarget();
       rv = retargetable->RetargetDeliveryTo(target);
     }
     PR_LOG(GetImgLog(), PR_LOG_WARNING,
            ("[this=%p] imgRequest::OnStartRequest -- "
             "RetargetDeliveryTo rv %d=%s\n",
             this, rv, NS_SUCCEEDED(rv) ? "succeeded" : "failed"));
   }