gecko-dev/gfx/2d/JobScheduler_win32.cpp

130 строки
3.0 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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);
}
virtual ~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 gfx
} // namespace mozilla