forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			210 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "DecodePool.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| #include "mozilla/ClearOnShutdown.h"
 | |
| #include "mozilla/DebugOnly.h"
 | |
| #include "mozilla/Monitor.h"
 | |
| #include "mozilla/ProfilerLabels.h"
 | |
| #include "mozilla/SchedulerGroup.h"
 | |
| #include "mozilla/Services.h"
 | |
| #include "mozilla/StaticPrefs_image.h"
 | |
| #include "mozilla/TaskController.h"
 | |
| #include "mozilla/TimeStamp.h"
 | |
| #include "mozilla/AppShutdown.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsIObserverService.h"
 | |
| #include "nsThreadManager.h"
 | |
| #include "nsThreadUtils.h"
 | |
| #include "nsXPCOMCIDInternal.h"
 | |
| #include "prsystem.h"
 | |
| 
 | |
| #include "Decoder.h"
 | |
| #include "IDecodingTask.h"
 | |
| #include "RasterImage.h"
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
| #  include <objbase.h>
 | |
| #  include "mozilla/WindowsProcessMitigations.h"
 | |
| #endif
 | |
| 
 | |
| using std::max;
 | |
| using std::min;
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace image {
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| // DecodePool implementation.
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| /* static */
 | |
| StaticRefPtr<DecodePool> DecodePool::sSingleton;
 | |
| /* static */
 | |
| uint32_t DecodePool::sNumCores = 0;
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
 | |
| 
 | |
| /* static */
 | |
| void DecodePool::Initialize() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   sNumCores = max<int32_t>(PR_GetNumberOfProcessors(), 1);
 | |
|   DecodePool::Singleton();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| DecodePool* DecodePool::Singleton() {
 | |
|   if (!sSingleton) {
 | |
|     MOZ_ASSERT(NS_IsMainThread());
 | |
|     sSingleton = new DecodePool();
 | |
|     ClearOnShutdown(&sSingleton);
 | |
|   }
 | |
| 
 | |
|   return sSingleton;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint32_t DecodePool::NumberOfCores() { return sNumCores; }
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
| class IOThreadIniter final : public Runnable {
 | |
|  public:
 | |
|   explicit IOThreadIniter() : Runnable("image::IOThreadIniter") {}
 | |
| 
 | |
|   NS_IMETHOD Run() override {
 | |
|     MOZ_ASSERT(!NS_IsMainThread());
 | |
| 
 | |
|     CoInitialize(nullptr);
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| #endif
 | |
| 
 | |
| DecodePool::DecodePool() : mMutex("image::IOThread") {
 | |
|   // Initialize the I/O thread.
 | |
| #if defined(XP_WIN)
 | |
|   // On Windows we use the io thread to get icons from the system. Any thread
 | |
|   // that makes system calls needs to call CoInitialize. And these system calls
 | |
|   // (SHGetFileInfo) should only be called from one thread at a time, in case
 | |
|   // we ever create more than one io thread. If win32k is locked down, we can't
 | |
|   // call SHGetFileInfo anyway, so we don't need the initializer.
 | |
|   nsCOMPtr<nsIRunnable> initer =
 | |
|       IsWin32kLockedDown() ? nullptr : new IOThreadIniter();
 | |
|   nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread), initer);
 | |
| #else
 | |
|   nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread));
 | |
| #endif
 | |
|   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() {
 | |
|   MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) {
 | |
|   MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
 | |
| 
 | |
|   mShuttingDown = true;
 | |
| 
 | |
|   nsCOMPtr<nsIThread> ioThread;
 | |
| 
 | |
|   {
 | |
|     MutexAutoLock lock(mMutex);
 | |
|     ioThread.swap(mIOThread);
 | |
|   }
 | |
| 
 | |
|   if (ioThread) {
 | |
|     ioThread->Shutdown();
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| /* static */ bool DecodePool::IsShuttingDown() {
 | |
|   if (MOZ_UNLIKELY(!sSingleton)) {
 | |
|     return AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads);
 | |
|   }
 | |
| 
 | |
|   return sSingleton->mShuttingDown;
 | |
| }
 | |
| 
 | |
| class DecodingTask final : public Task {
 | |
|  public:
 | |
|   explicit DecodingTask(RefPtr<IDecodingTask>&& aTask)
 | |
|       : Task(Kind::OffMainThreadOnly, aTask->Priority() == TaskPriority::eLow
 | |
|                                           ? EventQueuePriority::Normal
 | |
|                                           : EventQueuePriority::RenderBlocking),
 | |
|         mTask(aTask) {}
 | |
| 
 | |
|   TaskResult Run() override {
 | |
|     mTask->Run();
 | |
|     return TaskResult::Complete;
 | |
|   }
 | |
| 
 | |
| #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
 | |
|   bool GetName(nsACString& aName) override {
 | |
|     aName.AssignLiteral("ImageDecodingTask");
 | |
|     return true;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|  private:
 | |
|   RefPtr<IDecodingTask> mTask;
 | |
| };
 | |
| 
 | |
| void DecodePool::AsyncRun(IDecodingTask* aTask) {
 | |
|   MOZ_ASSERT(aTask);
 | |
| 
 | |
|   TaskController::Get()->AddTask(
 | |
|       MakeAndAddRef<DecodingTask>((RefPtr<IDecodingTask>(aTask))));
 | |
| }
 | |
| 
 | |
| bool DecodePool::SyncRunIfPreferred(IDecodingTask* aTask,
 | |
|                                     const nsCString& aURI) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   MOZ_ASSERT(aTask);
 | |
| 
 | |
|   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPreferred",
 | |
|                                         GRAPHICS, aURI);
 | |
| 
 | |
|   if (aTask->ShouldPreferSyncRun()) {
 | |
|     aTask->Run();
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   AsyncRun(aTask);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void DecodePool::SyncRunIfPossible(IDecodingTask* aTask,
 | |
|                                    const nsCString& aURI) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   MOZ_ASSERT(aTask);
 | |
| 
 | |
|   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPossible",
 | |
|                                         GRAPHICS, aURI);
 | |
| 
 | |
|   aTask->Run();
 | |
| }
 | |
| 
 | |
| already_AddRefed<nsISerialEventTarget> DecodePool::GetIOEventTarget() {
 | |
|   MutexAutoLock threadPoolLock(mMutex);
 | |
|   nsCOMPtr<nsISerialEventTarget> target = mIOThread;
 | |
|   return target.forget();
 | |
| }
 | |
| 
 | |
| }  // namespace image
 | |
| }  // namespace mozilla
 | 
