summaryrefslogtreecommitdiffstats
path: root/gfx/2d/JobScheduler_win32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/JobScheduler_win32.cpp')
-rw-r--r--gfx/2d/JobScheduler_win32.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/gfx/2d/JobScheduler_win32.cpp b/gfx/2d/JobScheduler_win32.cpp
new file mode 100644
index 000000000..989965adc
--- /dev/null
+++ b/gfx/2d/JobScheduler_win32.cpp
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 20; 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 "JobScheduler.h"
+#include "mozilla/gfx/Logging.h"
+
+using namespace std;
+
+namespace mozilla {
+namespace gfx {
+
+DWORD __stdcall ThreadCallback(void* threadData);
+
+class WorkerThreadWin32 : public WorkerThread {
+public:
+ explicit WorkerThreadWin32(MultiThreadedJobQueue* aJobQueue)
+ : WorkerThread(aJobQueue)
+ {
+ mThread = ::CreateThread(nullptr, 0, ThreadCallback, static_cast<WorkerThread*>(this), 0, nullptr);
+ }
+
+ ~WorkerThreadWin32()
+ {
+ ::WaitForSingleObject(mThread, INFINITE);
+ ::CloseHandle(mThread);
+ }
+
+protected:
+ HANDLE mThread;
+};
+
+DWORD __stdcall ThreadCallback(void* threadData)
+{
+ WorkerThread* thread = static_cast<WorkerThread*>(threadData);
+ thread->Run();
+ return 0;
+}
+
+WorkerThread*
+WorkerThread::Create(MultiThreadedJobQueue* aJobQueue)
+{
+ return new WorkerThreadWin32(aJobQueue);
+}
+
+bool
+MultiThreadedJobQueue::PopJob(Job*& aOutJob, AccessType aAccess)
+{
+ for (;;) {
+ while (aAccess == BLOCKING && mJobs.empty()) {
+ {
+ CriticalSectionAutoEnter lock(&mSection);
+ if (mShuttingDown) {
+ return false;
+ }
+ }
+
+ HANDLE handles[] = { mAvailableEvent, mShutdownEvent };
+ ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ }
+
+ CriticalSectionAutoEnter lock(&mSection);
+
+ if (mShuttingDown) {
+ return false;
+ }
+
+ if (mJobs.empty()) {
+ if (aAccess == NON_BLOCKING) {
+ return false;
+ }
+ continue;
+ }
+
+ Job* task = mJobs.front();
+ MOZ_ASSERT(task);
+
+ mJobs.pop_front();
+
+ if (mJobs.empty()) {
+ ::ResetEvent(mAvailableEvent);
+ }
+
+ aOutJob = task;
+ return true;
+ }
+}
+
+void
+MultiThreadedJobQueue::SubmitJob(Job* aJob)
+{
+ MOZ_ASSERT(aJob);
+ CriticalSectionAutoEnter lock(&mSection);
+ mJobs.push_back(aJob);
+ ::SetEvent(mAvailableEvent);
+}
+
+void
+MultiThreadedJobQueue::ShutDown()
+{
+ {
+ CriticalSectionAutoEnter lock(&mSection);
+ mShuttingDown = true;
+ }
+ while (mThreadsCount) {
+ ::SetEvent(mAvailableEvent);
+ ::WaitForSingleObject(mShutdownEvent, INFINITE);
+ }
+}
+
+size_t
+MultiThreadedJobQueue::NumJobs()
+{
+ CriticalSectionAutoEnter lock(&mSection);
+ return mJobs.size();
+}
+
+bool
+MultiThreadedJobQueue::IsEmpty()
+{
+ CriticalSectionAutoEnter lock(&mSection);
+ return mJobs.empty();
+}
+
+void
+MultiThreadedJobQueue::RegisterThread()
+{
+ mThreadsCount += 1;
+}
+
+void
+MultiThreadedJobQueue::UnregisterThread()
+{
+ mSection.Enter();
+ mThreadsCount -= 1;
+ bool finishShutdown = mThreadsCount == 0;
+ mSection.Leave();
+
+ if (finishShutdown) {
+ // Can't touch mSection or any other member from now on because this object
+ // may get deleted on the main thread after mShutdownEvent is set.
+ ::SetEvent(mShutdownEvent);
+ }
+}
+
+} // namespace
+} // namespace