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