tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DecodePool.cpp (5637B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "DecodePool.h"
      7 
      8 #include <algorithm>
      9 
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/Monitor.h"
     12 #include "mozilla/ProfilerLabels.h"
     13 #include "mozilla/SchedulerGroup.h"
     14 #include "mozilla/Services.h"
     15 #include "mozilla/StaticPrefs_image.h"
     16 #include "mozilla/TaskController.h"
     17 #include "mozilla/TimeStamp.h"
     18 #include "mozilla/AppShutdown.h"
     19 #include "nsCOMPtr.h"
     20 #include "nsIObserverService.h"
     21 #include "nsThreadManager.h"
     22 #include "nsThreadUtils.h"
     23 #include "nsXPCOMCIDInternal.h"
     24 #include "prsystem.h"
     25 
     26 #include "Decoder.h"
     27 #include "IDecodingTask.h"
     28 #include "RasterImage.h"
     29 
     30 #if defined(XP_WIN)
     31 #  include <objbase.h>
     32 #  include "mozilla/WindowsProcessMitigations.h"
     33 #endif
     34 
     35 using std::max;
     36 using std::min;
     37 
     38 namespace mozilla {
     39 namespace image {
     40 
     41 ///////////////////////////////////////////////////////////////////////////////
     42 // DecodePool implementation.
     43 ///////////////////////////////////////////////////////////////////////////////
     44 
     45 /* static */
     46 StaticRefPtr<DecodePool> DecodePool::sSingleton;
     47 /* static */
     48 uint32_t DecodePool::sNumCores = 0;
     49 
     50 NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
     51 
     52 /* static */
     53 void DecodePool::Initialize() {
     54  MOZ_ASSERT(NS_IsMainThread());
     55  sNumCores = max<int32_t>(PR_GetNumberOfProcessors(), 1);
     56  DecodePool::Singleton();
     57 }
     58 
     59 /* static */
     60 DecodePool* DecodePool::Singleton() {
     61  if (!sSingleton) {
     62    MOZ_ASSERT(NS_IsMainThread());
     63    sSingleton = new DecodePool();
     64    ClearOnShutdown(&sSingleton);
     65  }
     66 
     67  return sSingleton;
     68 }
     69 
     70 /* static */
     71 uint32_t DecodePool::NumberOfCores() { return sNumCores; }
     72 
     73 #if defined(XP_WIN)
     74 class IOThreadIniter final : public Runnable {
     75 public:
     76  explicit IOThreadIniter() : Runnable("image::IOThreadIniter") {}
     77 
     78  NS_IMETHOD Run() override {
     79    MOZ_ASSERT(!NS_IsMainThread());
     80 
     81    CoInitialize(nullptr);
     82 
     83    return NS_OK;
     84  }
     85 };
     86 #endif
     87 
     88 DecodePool::DecodePool() : mMutex("image::IOThread") {
     89  // Initialize the I/O thread.
     90 #if defined(XP_WIN)
     91  // On Windows we use the io thread to get icons from the system. Any thread
     92  // that makes system calls needs to call CoInitialize. And these system calls
     93  // (SHGetFileInfo) should only be called from one thread at a time, in case
     94  // we ever create more than one io thread. If win32k is locked down, we can't
     95  // call SHGetFileInfo anyway, so we don't need the initializer.
     96  nsCOMPtr<nsIRunnable> initer =
     97      IsWin32kLockedDown() ? nullptr : new IOThreadIniter();
     98  nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread), initer);
     99 #else
    100  nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread));
    101 #endif
    102  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOThread,
    103                     "Should successfully create image I/O thread");
    104 
    105  nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
    106  if (obsSvc) {
    107    obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
    108  }
    109 }
    110 
    111 DecodePool::~DecodePool() {
    112  MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
    113 }
    114 
    115 NS_IMETHODIMP
    116 DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) {
    117  MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
    118 
    119  mShuttingDown = true;
    120 
    121  nsCOMPtr<nsIThread> ioThread;
    122 
    123  {
    124    MutexAutoLock lock(mMutex);
    125    ioThread.swap(mIOThread);
    126  }
    127 
    128  if (ioThread) {
    129    ioThread->Shutdown();
    130  }
    131 
    132  return NS_OK;
    133 }
    134 
    135 /* static */ bool DecodePool::IsShuttingDown() {
    136  if (MOZ_UNLIKELY(!sSingleton)) {
    137    return AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads);
    138  }
    139 
    140  return sSingleton->mShuttingDown;
    141 }
    142 
    143 class DecodingTask final : public Task {
    144 public:
    145  explicit DecodingTask(RefPtr<IDecodingTask>&& aTask)
    146      : Task(Kind::OffMainThreadOnly, aTask->Priority() == TaskPriority::eLow
    147                                          ? EventQueuePriority::Normal
    148                                          : EventQueuePriority::RenderBlocking),
    149        mTask(aTask) {}
    150 
    151  TaskResult Run() override {
    152    mTask->Run();
    153    return TaskResult::Complete;
    154  }
    155 
    156 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
    157  bool GetName(nsACString& aName) override {
    158    aName.AssignLiteral("ImageDecodingTask");
    159    return true;
    160  }
    161 #endif
    162 
    163 private:
    164  RefPtr<IDecodingTask> mTask;
    165 };
    166 
    167 void DecodePool::AsyncRun(IDecodingTask* aTask) {
    168  MOZ_ASSERT(aTask);
    169 
    170  TaskController::Get()->AddTask(
    171      MakeAndAddRef<DecodingTask>((RefPtr<IDecodingTask>(aTask))));
    172 }
    173 
    174 bool DecodePool::SyncRunIfPreferred(IDecodingTask* aTask,
    175                                    const nsCString& aURI) {
    176  MOZ_ASSERT(NS_IsMainThread());
    177  MOZ_ASSERT(aTask);
    178 
    179  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPreferred",
    180                                        GRAPHICS, aURI);
    181 
    182  if (aTask->ShouldPreferSyncRun()) {
    183    aTask->Run();
    184    return true;
    185  }
    186 
    187  AsyncRun(aTask);
    188  return false;
    189 }
    190 
    191 void DecodePool::SyncRunIfPossible(IDecodingTask* aTask,
    192                                   const nsCString& aURI) {
    193  MOZ_ASSERT(NS_IsMainThread());
    194  MOZ_ASSERT(aTask);
    195 
    196  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPossible",
    197                                        GRAPHICS, aURI);
    198 
    199  aTask->Run();
    200 }
    201 
    202 already_AddRefed<nsISerialEventTarget> DecodePool::GetIOEventTarget() {
    203  MutexAutoLock threadPoolLock(mMutex);
    204  nsCOMPtr<nsISerialEventTarget> target = mIOThread;
    205  return target.forget();
    206 }
    207 
    208 }  // namespace image
    209 }  // namespace mozilla