Backed out 9 changesets (bug 1901851, bug 1728331) for causing remote worker crashes...
[gecko.git] / image / DecodePool.cpp
blob1f571cf38f9cab57067b7392d71d97caea1dd6c9
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 "mozilla/AppShutdown.h"
20 #include "nsCOMPtr.h"
21 #include "nsIObserverService.h"
22 #include "nsThreadManager.h"
23 #include "nsThreadUtils.h"
24 #include "nsXPCOMCIDInternal.h"
25 #include "prsystem.h"
27 #include "Decoder.h"
28 #include "IDecodingTask.h"
29 #include "RasterImage.h"
31 #if defined(XP_WIN)
32 # include <objbase.h>
33 # include "mozilla/WindowsProcessMitigations.h"
34 #endif
36 using std::max;
37 using std::min;
39 namespace mozilla {
40 namespace image {
42 ///////////////////////////////////////////////////////////////////////////////
43 // DecodePool implementation.
44 ///////////////////////////////////////////////////////////////////////////////
46 /* static */
47 StaticRefPtr<DecodePool> DecodePool::sSingleton;
48 /* static */
49 uint32_t DecodePool::sNumCores = 0;
51 NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
53 /* static */
54 void DecodePool::Initialize() {
55 MOZ_ASSERT(NS_IsMainThread());
56 sNumCores = max<int32_t>(PR_GetNumberOfProcessors(), 1);
57 DecodePool::Singleton();
60 /* static */
61 DecodePool* DecodePool::Singleton() {
62 if (!sSingleton) {
63 MOZ_ASSERT(NS_IsMainThread());
64 sSingleton = new DecodePool();
65 ClearOnShutdown(&sSingleton);
68 return sSingleton;
71 /* static */
72 uint32_t DecodePool::NumberOfCores() { return sNumCores; }
74 #if defined(XP_WIN)
75 class IOThreadIniter final : public Runnable {
76 public:
77 explicit IOThreadIniter() : Runnable("image::IOThreadIniter") {}
79 NS_IMETHOD Run() override {
80 MOZ_ASSERT(!NS_IsMainThread());
82 CoInitialize(nullptr);
84 return NS_OK;
87 #endif
89 DecodePool::DecodePool() : mMutex("image::IOThread") {
90 // Initialize the I/O thread.
91 #if defined(XP_WIN)
92 // On Windows we use the io thread to get icons from the system. Any thread
93 // that makes system calls needs to call CoInitialize. And these system calls
94 // (SHGetFileInfo) should only be called from one thread at a time, in case
95 // we ever create more than one io thread. If win32k is locked down, we can't
96 // call SHGetFileInfo anyway, so we don't need the initializer.
97 nsCOMPtr<nsIRunnable> initer =
98 IsWin32kLockedDown() ? nullptr : new IOThreadIniter();
99 nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread), initer);
100 #else
101 nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread));
102 #endif
103 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOThread,
104 "Should successfully create image I/O thread");
106 nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
107 if (obsSvc) {
108 obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
112 DecodePool::~DecodePool() {
113 MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
116 NS_IMETHODIMP
117 DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) {
118 MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic");
120 mShuttingDown = true;
122 nsCOMPtr<nsIThread> ioThread;
125 MutexAutoLock lock(mMutex);
126 ioThread.swap(mIOThread);
129 if (ioThread) {
130 ioThread->Shutdown();
133 return NS_OK;
136 /* static */ bool DecodePool::IsShuttingDown() {
137 if (MOZ_UNLIKELY(!sSingleton)) {
138 return AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads);
141 return sSingleton->mShuttingDown;
144 class DecodingTask final : public Task {
145 public:
146 explicit DecodingTask(RefPtr<IDecodingTask>&& aTask)
147 : Task(Kind::OffMainThreadOnly, aTask->Priority() == TaskPriority::eLow
148 ? EventQueuePriority::Normal
149 : EventQueuePriority::RenderBlocking),
150 mTask(aTask) {}
152 TaskResult Run() override {
153 mTask->Run();
154 return TaskResult::Complete;
157 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
158 bool GetName(nsACString& aName) override {
159 aName.AssignLiteral("ImageDecodingTask");
160 return true;
162 #endif
164 private:
165 RefPtr<IDecodingTask> mTask;
168 void DecodePool::AsyncRun(IDecodingTask* aTask) {
169 MOZ_ASSERT(aTask);
171 TaskController::Get()->AddTask(
172 MakeAndAddRef<DecodingTask>((RefPtr<IDecodingTask>(aTask))));
175 bool DecodePool::SyncRunIfPreferred(IDecodingTask* aTask,
176 const nsCString& aURI) {
177 MOZ_ASSERT(NS_IsMainThread());
178 MOZ_ASSERT(aTask);
180 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPreferred",
181 GRAPHICS, aURI);
183 if (aTask->ShouldPreferSyncRun()) {
184 aTask->Run();
185 return true;
188 AsyncRun(aTask);
189 return false;
192 void DecodePool::SyncRunIfPossible(IDecodingTask* aTask,
193 const nsCString& aURI) {
194 MOZ_ASSERT(NS_IsMainThread());
195 MOZ_ASSERT(aTask);
197 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPossible",
198 GRAPHICS, aURI);
200 aTask->Run();
203 already_AddRefed<nsISerialEventTarget> DecodePool::GetIOEventTarget() {
204 MutexAutoLock threadPoolLock(mMutex);
205 nsCOMPtr<nsISerialEventTarget> target = mIOThread;
206 return target.forget();
209 } // namespace image
210 } // namespace mozilla