Bug 1829125 - Align the PHC area to the jemalloc chunk size r=glandium
[gecko.git] / image / DecodePool.cpp
blob753e53727ce80262e4d06609547ef65068c4c94b
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/. */
6 #include "DecodePool.h"
8 #include <algorithm>
10 #include "mozilla/ClearOnShutdown.h"
11 #include "mozilla/DebugOnly.h"
12 #include "mozilla/Monitor.h"
13 #include "mozilla/ProfilerLabels.h"
14 #include "mozilla/SchedulerGroup.h"
15 #include "mozilla/Services.h"
16 #include "mozilla/StaticPrefs_image.h"
17 #include "mozilla/TaskController.h"
18 #include "mozilla/TimeStamp.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"
26 #include "Decoder.h"
27 #include "IDecodingTask.h"
28 #include "RasterImage.h"
30 #if defined(XP_WIN)
31 # include <objbase.h>
32 # include "mozilla/WindowsProcessMitigations.h"
33 #endif
35 using std::max;
36 using std::min;
38 namespace mozilla {
39 namespace image {
41 ///////////////////////////////////////////////////////////////////////////////
42 // DecodePool implementation.
43 ///////////////////////////////////////////////////////////////////////////////
45 /* static */
46 StaticRefPtr<DecodePool> DecodePool::sSingleton;
47 /* static */
48 uint32_t DecodePool::sNumCores = 0;
50 NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
52 /* static */
53 void DecodePool::Initialize() {
54 MOZ_ASSERT(NS_IsMainThread());
55 sNumCores = max<int32_t>(PR_GetNumberOfProcessors(), 1);
56 DecodePool::Singleton();
59 /* static */
60 DecodePool* DecodePool::Singleton() {
61 if (!sSingleton) {
62 MOZ_ASSERT(NS_IsMainThread());
63 sSingleton = new DecodePool();
64 ClearOnShutdown(&sSingleton);
67 return sSingleton;
70 /* static */
71 uint32_t DecodePool::NumberOfCores() { return sNumCores; }
73 #if defined(XP_WIN)
74 class IOThreadIniter final : public Runnable {
75 public:
76 explicit IOThreadIniter() : Runnable("image::IOThreadIniter") {}
78 NS_IMETHOD Run() override {
79 MOZ_ASSERT(!NS_IsMainThread());
81 CoInitialize(nullptr);
83 return NS_OK;
86 #endif
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");
105 nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
106 if (obsSvc) {
107 obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
111 DecodePool::~DecodePool() {
112 MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
115 NS_IMETHODIMP
116 DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) {
117 MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
119 mShuttingDown = true;
121 nsCOMPtr<nsIThread> ioThread;
124 MutexAutoLock lock(mMutex);
125 ioThread.swap(mIOThread);
128 if (ioThread) {
129 ioThread->Shutdown();
132 return NS_OK;
135 bool DecodePool::IsShuttingDown() const { return mShuttingDown; }
137 class DecodingTask final : public Task {
138 public:
139 explicit DecodingTask(RefPtr<IDecodingTask>&& aTask)
140 : Task(false, aTask->Priority() == TaskPriority::eLow
141 ? EventQueuePriority::Normal
142 : EventQueuePriority::RenderBlocking),
143 mTask(aTask) {}
145 bool Run() override {
146 mTask->Run();
147 return true;
150 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
151 bool GetName(nsACString& aName) override {
152 aName.AssignLiteral("ImageDecodingTask");
153 return true;
155 #endif
157 private:
158 RefPtr<IDecodingTask> mTask;
161 void DecodePool::AsyncRun(IDecodingTask* aTask) {
162 MOZ_ASSERT(aTask);
164 TaskController::Get()->AddTask(
165 MakeAndAddRef<DecodingTask>((RefPtr<IDecodingTask>(aTask))));
168 bool DecodePool::SyncRunIfPreferred(IDecodingTask* aTask,
169 const nsCString& aURI) {
170 MOZ_ASSERT(NS_IsMainThread());
171 MOZ_ASSERT(aTask);
173 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPreferred",
174 GRAPHICS, aURI);
176 if (aTask->ShouldPreferSyncRun()) {
177 aTask->Run();
178 return true;
181 AsyncRun(aTask);
182 return false;
185 void DecodePool::SyncRunIfPossible(IDecodingTask* aTask,
186 const nsCString& aURI) {
187 MOZ_ASSERT(NS_IsMainThread());
188 MOZ_ASSERT(aTask);
190 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPossible",
191 GRAPHICS, aURI);
193 aTask->Run();
196 already_AddRefed<nsISerialEventTarget> DecodePool::GetIOEventTarget() {
197 MutexAutoLock threadPoolLock(mMutex);
198 nsCOMPtr<nsISerialEventTarget> target = mIOThread;
199 return target.forget();
202 } // namespace image
203 } // namespace mozilla