зеркало из https://github.com/mozilla/gecko-dev.git
130 строки
3.0 KiB
C++
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
|