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"
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"
20 #include "nsIObserverService.h"
21 #include "nsThreadManager.h"
22 #include "nsThreadUtils.h"
23 #include "nsXPCOMCIDInternal.h"
27 #include "IDecodingTask.h"
28 #include "RasterImage.h"
32 # include "mozilla/WindowsProcessMitigations.h"
41 ///////////////////////////////////////////////////////////////////////////////
42 // DecodePool implementation.
43 ///////////////////////////////////////////////////////////////////////////////
46 StaticRefPtr
<DecodePool
> DecodePool::sSingleton
;
48 uint32_t DecodePool::sNumCores
= 0;
50 NS_IMPL_ISUPPORTS(DecodePool
, nsIObserver
)
53 void DecodePool::Initialize() {
54 MOZ_ASSERT(NS_IsMainThread());
55 sNumCores
= max
<int32_t>(PR_GetNumberOfProcessors(), 1);
56 DecodePool::Singleton();
60 DecodePool
* DecodePool::Singleton() {
62 MOZ_ASSERT(NS_IsMainThread());
63 sSingleton
= new DecodePool();
64 ClearOnShutdown(&sSingleton
);
71 uint32_t DecodePool::NumberOfCores() { return sNumCores
; }
74 class IOThreadIniter final
: public Runnable
{
76 explicit IOThreadIniter() : Runnable("image::IOThreadIniter") {}
78 NS_IMETHOD
Run() override
{
79 MOZ_ASSERT(!NS_IsMainThread());
81 CoInitialize(nullptr);
88 DecodePool::DecodePool() : mMutex("image::IOThread") {
89 // Initialize the I/O thread.
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
);
100 nsresult rv
= NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread
));
102 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
) && mIOThread
,
103 "Should successfully create image I/O thread");
105 nsCOMPtr
<nsIObserverService
> obsSvc
= services::GetObserverService();
107 obsSvc
->AddObserver(this, "xpcom-shutdown-threads", false);
111 DecodePool::~DecodePool() {
112 MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
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
);
129 ioThread
->Shutdown();
135 bool DecodePool::IsShuttingDown() const { return mShuttingDown
; }
137 class DecodingTask final
: public Task
{
139 explicit DecodingTask(RefPtr
<IDecodingTask
>&& aTask
)
140 : Task(Kind::OffMainThreadOnly
, aTask
->Priority() == TaskPriority::eLow
141 ? EventQueuePriority::Normal
142 : EventQueuePriority::RenderBlocking
),
145 TaskResult
Run() override
{
147 return TaskResult::Complete
;
150 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
151 bool GetName(nsACString
& aName
) override
{
152 aName
.AssignLiteral("ImageDecodingTask");
158 RefPtr
<IDecodingTask
> mTask
;
161 void DecodePool::AsyncRun(IDecodingTask
* 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());
173 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPreferred",
176 if (aTask
->ShouldPreferSyncRun()) {
185 void DecodePool::SyncRunIfPossible(IDecodingTask
* aTask
,
186 const nsCString
& aURI
) {
187 MOZ_ASSERT(NS_IsMainThread());
190 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("DecodePool::SyncRunIfPossible",
196 already_AddRefed
<nsISerialEventTarget
> DecodePool::GetIOEventTarget() {
197 MutexAutoLock
threadPoolLock(mMutex
);
198 nsCOMPtr
<nsISerialEventTarget
> target
= mIOThread
;
199 return target
.forget();
203 } // namespace mozilla