From 29a704eea3427545ba1670f7ccead1a592812eae Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Sun, 18 Jan 2015 01:27:16 -0800 Subject: [PATCH] Bug 1119158 - Retarget OnDataAvailable to a new I/O thread instead of the image decoding thread pool. r=sworkman --- image/build/nsImageModule.cpp | 4 +- image/src/DecodePool.cpp | 87 ++++++++++++++++++++++++----------- image/src/DecodePool.h | 21 +++++++-- image/src/RasterImage.cpp | 8 ---- image/src/RasterImage.h | 2 - image/src/imgRequest.cpp | 5 +- 6 files changed, 82 insertions(+), 45 deletions(-) diff --git a/image/build/nsImageModule.cpp b/image/build/nsImageModule.cpp index 3438701c129..6bc4c04a6b4 100644 --- a/image/build/nsImageModule.cpp +++ b/image/build/nsImageModule.cpp @@ -9,8 +9,8 @@ #include "mozilla/ModuleUtils.h" #include "nsMimeTypes.h" +#include "DecodePool.h" #include "ImageFactory.h" -#include "RasterImage.h" #include "ShutdownTracker.h" #include "SurfaceCache.h" @@ -92,7 +92,7 @@ mozilla::image::InitModule() mozilla::image::ShutdownTracker::Initialize(); mozilla::image::ImageFactory::Initialize(); - mozilla::image::RasterImage::Initialize(); + mozilla::image::DecodePool::Initialize(); mozilla::image::SurfaceCache::Initialize(); imgLoader::GlobalInit(); sInitialized = true; diff --git a/image/src/DecodePool.cpp b/image/src/DecodePool.cpp index e747454e8c6..95f8d9ab2ca 100644 --- a/image/src/DecodePool.cpp +++ b/image/src/DecodePool.cpp @@ -12,6 +12,7 @@ #include "nsCOMPtr.h" #include "nsIObserverService.h" #include "nsIThreadPool.h" +#include "nsThreadUtils.h" #include "nsXPCOMCIDInternal.h" #include "prsystem.h" @@ -127,35 +128,36 @@ private: #ifdef MOZ_NUWA_PROCESS -class RIDThreadPoolListener MOZ_FINAL : public nsIThreadPoolListener +class DecodePoolNuwaListener MOZ_FINAL : public nsIThreadPoolListener { public: NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSITHREADPOOLLISTENER - - RIDThreadPoolListener() { } -private: - ~RIDThreadPoolListener() { } -}; - -NS_IMPL_ISUPPORTS(RIDThreadPoolListener, nsIThreadPoolListener) - -NS_IMETHODIMP -RIDThreadPoolListener::OnThreadCreated() -{ + NS_IMETHODIMP OnThreadCreated() + { if (IsNuwaProcess()) { - NuwaMarkCurrentThread(static_cast(nullptr), nullptr); + NuwaMarkCurrentThread(static_cast(nullptr), nullptr); } return NS_OK; -} + } -NS_IMETHODIMP -RIDThreadPoolListener::OnThreadShuttingDown() + NS_IMETHODIMP OnThreadShuttingDown() { return NS_OK; } + +private: + ~DecodePoolNuwaListener() { } +}; + +NS_IMPL_ISUPPORTS(DecodePoolNuwaListener, nsIThreadPoolListener) + +class RegisterDecodeIOThreadWithNuwaRunnable : public nsRunnable { +public: + NS_IMETHOD Run() + { + NuwaMarkCurrentThread(static_cast(nullptr), nullptr); return NS_OK; -} - + } +}; #endif // MOZ_NUWA_PROCESS @@ -167,6 +169,13 @@ RIDThreadPoolListener::OnThreadShuttingDown() NS_IMPL_ISUPPORTS(DecodePool, nsIObserver) +/* static */ void +DecodePool::Initialize() +{ + MOZ_ASSERT(NS_IsMainThread()); + DecodePool::Singleton(); +} + /* static */ DecodePool* DecodePool::Singleton() { @@ -180,8 +189,9 @@ DecodePool::Singleton() } DecodePool::DecodePool() - : mThreadPoolMutex("Thread Pool") + : mMutex("image::DecodePool") { + // Initialize the thread pool. mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID); MOZ_RELEASE_ASSERT(mThreadPool, "Should succeed in creating image decoding thread pool"); @@ -200,10 +210,22 @@ DecodePool::DecodePool() #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { - mThreadPool->SetListener(new RIDThreadPoolListener()); + mThreadPool->SetListener(new DecodePoolNuwaListener()); } #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"); + +#ifdef MOZ_NUWA_PROCESS + nsCOMPtr worker = new RegisterDecodeIOThreadWithNuwaRunnable(); + rv = mIOThread->Dispatch(worker, NS_DISPATCH_NORMAL); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), + "Should register decode IO thread with Nuwa process"); +#endif + nsCOMPtr obsSvc = services::GetObserverService(); if (obsSvc) { obsSvc->AddObserver(this, "xpcom-shutdown-threads", false); @@ -221,17 +243,22 @@ DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic"); nsCOMPtr threadPool; + nsCOMPtr 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; } @@ -244,7 +271,7 @@ DecodePool::AsyncDecode(Decoder* 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); } @@ -274,11 +301,19 @@ DecodePool::SyncDecodeIfPossible(Decoder* aDecoder) already_AddRefed DecodePool::GetEventTarget() { - MutexAutoLock threadPoolLock(mThreadPoolMutex); + MutexAutoLock threadPoolLock(mMutex); nsCOMPtr target = do_QueryInterface(mThreadPool); return target.forget(); } +already_AddRefed +DecodePool::GetIOEventTarget() +{ + MutexAutoLock threadPoolLock(mMutex); + nsCOMPtr target = do_QueryInterface(mIOThread); + return target.forget(); +} + already_AddRefed DecodePool::CreateDecodeWorker(Decoder* aDecoder) { diff --git a/image/src/DecodePool.h b/image/src/DecodePool.h index b21b7fd9c85..4daac25f3b8 100644 --- a/image/src/DecodePool.h +++ b/image/src/DecodePool.h @@ -17,6 +17,7 @@ #include "nsIEventTarget.h" #include "nsIObserver.h" +class nsIThread; class nsIThreadPool; namespace mozilla { @@ -41,6 +42,10 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVER + /// Initializes the singleton instance. Should be called from the main thread. + static void Initialize(); + + /// Returns the singleton instance. static DecodePool* Singleton(); /// Ask the DecodePool to run @aDecoder asynchronously and return immediately. @@ -69,6 +74,15 @@ public: */ already_AddRefed 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 GetIOEventTarget(); + /** * Creates a worker which can be used to attempt further decoding using the * provided decoder. @@ -91,11 +105,10 @@ private: static StaticRefPtr 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 mThreadPool; + nsCOMPtr mIOThread; }; } // namespace image diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 5811467263c..b3ede0c72f8 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -297,14 +297,6 @@ RasterImage::~RasterImage() SurfaceCache::RemoveImage(ImageKey(this)); } -/* static */ void -RasterImage::Initialize() -{ - // Create our singletons now, so we don't have to worry about what thread - // they're created on. - DecodePool::Singleton(); -} - nsresult RasterImage::Init(const char* aMimeType, uint32_t aFlags) diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index ced96781359..4f48a76ab12 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -280,8 +280,6 @@ public: return spec; } - static void Initialize(); - private: void DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef, gfxContext* aContext, diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp index 1f1780fbb0e..2483538c065 100644 --- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -699,10 +699,9 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt 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 target = - DecodePool::Singleton()->GetEventTarget(); + DecodePool::Singleton()->GetIOEventTarget(); rv = retargetable->RetargetDeliveryTo(target); } PR_LOG(GetImgLog(), PR_LOG_WARNING,