Bug 1119158 - Retarget OnDataAvailable to a new I/O thread instead of the image decoding thread pool. r=sworkman

This commit is contained in:
Seth Fowler 2015-01-18 01:27:16 -08:00
parent f63da28c3b
commit 29a704eea3
6 changed files with 82 additions and 45 deletions

View File

@ -9,8 +9,8 @@
#include "mozilla/ModuleUtils.h" #include "mozilla/ModuleUtils.h"
#include "nsMimeTypes.h" #include "nsMimeTypes.h"
#include "DecodePool.h"
#include "ImageFactory.h" #include "ImageFactory.h"
#include "RasterImage.h"
#include "ShutdownTracker.h" #include "ShutdownTracker.h"
#include "SurfaceCache.h" #include "SurfaceCache.h"
@ -92,7 +92,7 @@ mozilla::image::InitModule()
mozilla::image::ShutdownTracker::Initialize(); mozilla::image::ShutdownTracker::Initialize();
mozilla::image::ImageFactory::Initialize(); mozilla::image::ImageFactory::Initialize();
mozilla::image::RasterImage::Initialize(); mozilla::image::DecodePool::Initialize();
mozilla::image::SurfaceCache::Initialize(); mozilla::image::SurfaceCache::Initialize();
imgLoader::GlobalInit(); imgLoader::GlobalInit();
sInitialized = true; sInitialized = true;

View File

@ -12,6 +12,7 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsIThreadPool.h" #include "nsIThreadPool.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h" #include "nsXPCOMCIDInternal.h"
#include "prsystem.h" #include "prsystem.h"
@ -127,35 +128,36 @@ private:
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
class RIDThreadPoolListener MOZ_FINAL : public nsIThreadPoolListener class DecodePoolNuwaListener MOZ_FINAL : public nsIThreadPoolListener
{ {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITHREADPOOLLISTENER
RIDThreadPoolListener() { }
private: NS_IMETHODIMP OnThreadCreated()
~RIDThreadPoolListener() { } {
};
NS_IMPL_ISUPPORTS(RIDThreadPoolListener, nsIThreadPoolListener)
NS_IMETHODIMP
RIDThreadPoolListener::OnThreadCreated()
{
if (IsNuwaProcess()) { if (IsNuwaProcess()) {
NuwaMarkCurrentThread(static_cast<void(*)(void*)>(nullptr), nullptr); NuwaMarkCurrentThread(static_cast<void(*)(void*)>(nullptr), nullptr);
} }
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP OnThreadShuttingDown() { return NS_OK; }
RIDThreadPoolListener::OnThreadShuttingDown()
private:
~DecodePoolNuwaListener() { }
};
NS_IMPL_ISUPPORTS(DecodePoolNuwaListener, nsIThreadPoolListener)
class RegisterDecodeIOThreadWithNuwaRunnable : public nsRunnable
{ {
public:
NS_IMETHOD Run()
{
NuwaMarkCurrentThread(static_cast<void(*)(void*)>(nullptr), nullptr);
return NS_OK; return NS_OK;
} }
};
#endif // MOZ_NUWA_PROCESS #endif // MOZ_NUWA_PROCESS
@ -167,6 +169,13 @@ RIDThreadPoolListener::OnThreadShuttingDown()
NS_IMPL_ISUPPORTS(DecodePool, nsIObserver) NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
/* static */ void
DecodePool::Initialize()
{
MOZ_ASSERT(NS_IsMainThread());
DecodePool::Singleton();
}
/* static */ DecodePool* /* static */ DecodePool*
DecodePool::Singleton() DecodePool::Singleton()
{ {
@ -180,8 +189,9 @@ DecodePool::Singleton()
} }
DecodePool::DecodePool() DecodePool::DecodePool()
: mThreadPoolMutex("Thread Pool") : mMutex("image::DecodePool")
{ {
// Initialize the thread pool.
mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID); mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
MOZ_RELEASE_ASSERT(mThreadPool, MOZ_RELEASE_ASSERT(mThreadPool,
"Should succeed in creating image decoding thread pool"); "Should succeed in creating image decoding thread pool");
@ -200,10 +210,22 @@ DecodePool::DecodePool()
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) { if (IsNuwaProcess()) {
mThreadPool->SetListener(new RIDThreadPoolListener()); mThreadPool->SetListener(new DecodePoolNuwaListener());
} }
#endif #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<nsIRunnable> 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<nsIObserverService> obsSvc = services::GetObserverService(); nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
if (obsSvc) { if (obsSvc) {
obsSvc->AddObserver(this, "xpcom-shutdown-threads", false); 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"); MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
nsCOMPtr<nsIThreadPool> threadPool; nsCOMPtr<nsIThreadPool> threadPool;
nsCOMPtr<nsIThread> ioThread;
{ {
MutexAutoLock threadPoolLock(mThreadPoolMutex); MutexAutoLock lock(mMutex);
threadPool = mThreadPool; threadPool.swap(mThreadPool);
mThreadPool = nullptr; ioThread.swap(mIOThread);
} }
if (threadPool) { if (threadPool) {
threadPool->Shutdown(); threadPool->Shutdown();
} }
if (ioThread) {
ioThread->Shutdown();
}
return NS_OK; 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 // 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. // shutting down, so it's OK to just drop the job on the floor.
MutexAutoLock threadPoolLock(mThreadPoolMutex); MutexAutoLock threadPoolLock(mMutex);
if (mThreadPool) { if (mThreadPool) {
mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL); mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL);
} }
@ -274,11 +301,19 @@ DecodePool::SyncDecodeIfPossible(Decoder* aDecoder)
already_AddRefed<nsIEventTarget> already_AddRefed<nsIEventTarget>
DecodePool::GetEventTarget() DecodePool::GetEventTarget()
{ {
MutexAutoLock threadPoolLock(mThreadPoolMutex); MutexAutoLock threadPoolLock(mMutex);
nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool); nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
return target.forget(); return target.forget();
} }
already_AddRefed<nsIEventTarget>
DecodePool::GetIOEventTarget()
{
MutexAutoLock threadPoolLock(mMutex);
nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mIOThread);
return target.forget();
}
already_AddRefed<nsIRunnable> already_AddRefed<nsIRunnable>
DecodePool::CreateDecodeWorker(Decoder* aDecoder) DecodePool::CreateDecodeWorker(Decoder* aDecoder)
{ {

View File

@ -17,6 +17,7 @@
#include "nsIEventTarget.h" #include "nsIEventTarget.h"
#include "nsIObserver.h" #include "nsIObserver.h"
class nsIThread;
class nsIThreadPool; class nsIThreadPool;
namespace mozilla { namespace mozilla {
@ -41,6 +42,10 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
/// Initializes the singleton instance. Should be called from the main thread.
static void Initialize();
/// Returns the singleton instance.
static DecodePool* Singleton(); static DecodePool* Singleton();
/// Ask the DecodePool to run @aDecoder asynchronously and return immediately. /// Ask the DecodePool to run @aDecoder asynchronously and return immediately.
@ -69,6 +74,15 @@ public:
*/ */
already_AddRefed<nsIEventTarget> GetEventTarget(); 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 * Creates a worker which can be used to attempt further decoding using the
* provided decoder. * provided decoder.
@ -91,11 +105,10 @@ private:
static StaticRefPtr<DecodePool> sSingleton; static StaticRefPtr<DecodePool> sSingleton;
// mThreadPoolMutex protects mThreadPool. For all RasterImages R, // mMutex protects mThreadPool and mIOThread.
// R::mDecodingMonitor must be acquired before mThreadPoolMutex Mutex mMutex;
// if both are acquired; the other order may cause deadlock.
Mutex mThreadPoolMutex;
nsCOMPtr<nsIThreadPool> mThreadPool; nsCOMPtr<nsIThreadPool> mThreadPool;
nsCOMPtr<nsIThread> mIOThread;
}; };
} // namespace image } // namespace image

View File

@ -297,14 +297,6 @@ RasterImage::~RasterImage()
SurfaceCache::RemoveImage(ImageKey(this)); 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 nsresult
RasterImage::Init(const char* aMimeType, RasterImage::Init(const char* aMimeType,
uint32_t aFlags) uint32_t aFlags)

View File

@ -280,8 +280,6 @@ public:
return spec; return spec;
} }
static void Initialize();
private: private:
void DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef, void DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
gfxContext* aContext, gfxContext* aContext,

View File

@ -699,10 +699,9 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
nsAutoCString mimeType; nsAutoCString mimeType;
nsresult rv = httpChannel->GetContentType(mimeType); nsresult rv = httpChannel->GetContentType(mimeType);
if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) { if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
// Image object not created until OnDataAvailable, so forward to static // Retarget OnDataAvailable to the DecodePool's IO thread.
// DecodePool directly.
nsCOMPtr<nsIEventTarget> target = nsCOMPtr<nsIEventTarget> target =
DecodePool::Singleton()->GetEventTarget(); DecodePool::Singleton()->GetIOEventTarget();
rv = retargetable->RetargetDeliveryTo(target); rv = retargetable->RetargetDeliveryTo(target);
} }
PR_LOG(GetImgLog(), PR_LOG_WARNING, PR_LOG(GetImgLog(), PR_LOG_WARNING,