summaryrefslogtreecommitdiffstats
path: root/image/DecodePool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/DecodePool.cpp')
-rw-r--r--image/DecodePool.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/image/DecodePool.cpp b/image/DecodePool.cpp
new file mode 100644
index 0000000000..b633226914
--- /dev/null
+++ b/image/DecodePool.cpp
@@ -0,0 +1,203 @@
+/* -*- 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 "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;
+}
+
+bool DecodePool::IsShuttingDown() const { return 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