mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			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
 |