Skip to content
This repository was archived by the owner on Dec 15, 2018. It is now read-only.

Commit 120cce1

Browse files
committed
Bug 1083101 - Win32 implementation of the JobScheduler. r=jrmuizel
1 parent a5f1897 commit 120cce1

File tree

8 files changed

+328
-106
lines changed

8 files changed

+328
-106
lines changed

gfx/2d/JobScheduler.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ bool JobScheduler::Init(uint32_t aNumThreads, uint32_t aNumQueues)
2323
}
2424

2525
for (uint32_t i = 0; i < aNumThreads; ++i) {
26-
sSingleton->mWorkerThreads.push_back(new WorkerThread(sSingleton->mDrawingQueues[i%aNumQueues]));
26+
sSingleton->mWorkerThreads.push_back(WorkerThread::Create(sSingleton->mDrawingQueues[i%aNumQueues]));
2727
}
2828
return true;
2929
}
@@ -232,5 +232,33 @@ SyncObject::AddSubsequent(Job* aJob)
232232
{
233233
}
234234

235+
WorkerThread::WorkerThread(MultiThreadedJobQueue* aJobQueue)
236+
: mQueue(aJobQueue)
237+
{
238+
aJobQueue->RegisterThread();
239+
}
240+
241+
void
242+
WorkerThread::Run()
243+
{
244+
SetName("gfx worker");
245+
246+
for (;;) {
247+
Job* commands = nullptr;
248+
if (!mQueue->WaitForJob(commands)) {
249+
mQueue->UnregisterThread();
250+
return;
251+
}
252+
253+
JobStatus status = JobScheduler::ProcessJob(commands);
254+
255+
if (status == JobStatus::Error) {
256+
// Don't try to handle errors for now, but that's open to discussions.
257+
// I expect errors to be mostly OOM issues.
258+
MOZ_CRASH();
259+
}
260+
}
261+
}
262+
235263
} //namespace
236264
} //namespace

gfx/2d/JobScheduler.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
#include "mozilla/gfx/JobScheduler_posix.h"
1616
#endif
1717

18+
#include <vector>
19+
1820
namespace mozilla {
1921
namespace gfx {
2022

2123
class MultiThreadedJobQueue;
2224
class SyncObject;
25+
class WorkerThread;
2326

2427
class JobScheduler {
2528
public:
@@ -224,6 +227,25 @@ struct MutexAutoLock {
224227
Mutex* mMutex;
225228
};
226229

230+
/// Base class for worker threads.
231+
class WorkerThread
232+
{
233+
public:
234+
static WorkerThread* Create(MultiThreadedJobQueue* aJobQueue);
235+
236+
virtual ~WorkerThread() {}
237+
238+
void Run();
239+
240+
MultiThreadedJobQueue* GetJobQueue() { return mQueue; }
241+
242+
protected:
243+
explicit WorkerThread(MultiThreadedJobQueue* aJobQueue);
244+
245+
virtual void SetName(const char* aName) {}
246+
247+
MultiThreadedJobQueue* mQueue;
248+
};
227249

228250
} // namespace
229251
} // namespace

gfx/2d/JobScheduler_posix.cpp

Lines changed: 46 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,52 @@ using namespace std;
1111
namespace mozilla {
1212
namespace gfx {
1313

14+
void* ThreadCallback(void* threadData);
15+
16+
class WorkerThreadPosix : public WorkerThread {
17+
public:
18+
explicit WorkerThreadPosix(MultiThreadedJobQueue* aJobQueue)
19+
: WorkerThread(aJobQueue)
20+
{
21+
pthread_create(&mThread, nullptr, ThreadCallback, static_cast<WorkerThread*>(this));
22+
}
23+
24+
~WorkerThreadPosix()
25+
{
26+
pthread_join(mThread, nullptr);
27+
}
28+
29+
virtual void SetName(const char* aName) override
30+
{
31+
// Call this from the thread itself because of Mac.
32+
#ifdef XP_MACOSX
33+
pthread_setname_np(aName);
34+
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
35+
pthread_set_name_np(mThread, aName);
36+
#elif defined(__NetBSD__)
37+
pthread_setname_np(mThread, "%s", (void*)aName);
38+
#else
39+
pthread_setname_np(mThread, aName);
40+
#endif
41+
}
42+
43+
protected:
44+
pthread_t mThread;
45+
};
46+
47+
void* ThreadCallback(void* threadData)
48+
{
49+
WorkerThread* thread = static_cast<WorkerThread*>(threadData);
50+
thread->Run();
51+
return nullptr;
52+
}
53+
54+
WorkerThread*
55+
WorkerThread::Create(MultiThreadedJobQueue* aJobQueue)
56+
{
57+
return new WorkerThreadPosix(aJobQueue);
58+
}
59+
1460
MultiThreadedJobQueue::MultiThreadedJobQueue()
1561
: mThreadsCount(0)
1662
, mShuttingDown(false)
@@ -108,62 +154,6 @@ MultiThreadedJobQueue::UnregisterThread()
108154
}
109155
}
110156

111-
void* ThreadCallback(void* threadData)
112-
{
113-
WorkerThread* thread = (WorkerThread*)threadData;
114-
thread->Run();
115-
return nullptr;
116-
}
117-
118-
WorkerThread::WorkerThread(MultiThreadedJobQueue* aJobQueue)
119-
: mQueue(aJobQueue)
120-
{
121-
aJobQueue->RegisterThread();
122-
pthread_create(&mThread, nullptr, ThreadCallback, this);
123-
}
124-
125-
WorkerThread::~WorkerThread()
126-
{
127-
pthread_join(mThread, nullptr);
128-
}
129-
130-
void
131-
WorkerThread::SetName(const char* aName)
132-
{
133-
// Call this from the thread itself because of Mac.
134-
#ifdef XP_MACOSX
135-
pthread_setname_np(aName);
136-
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
137-
pthread_set_name_np(mThread, aName);
138-
#elif defined(__NetBSD__)
139-
pthread_setname_np(mThread, "%s", (void*)aName);
140-
#else
141-
pthread_setname_np(mThread, aName);
142-
#endif
143-
}
144-
145-
void
146-
WorkerThread::Run()
147-
{
148-
SetName("gfx worker");
149-
150-
for (;;) {
151-
Job* commands = nullptr;
152-
if (!mQueue->WaitForJob(commands)) {
153-
mQueue->UnregisterThread();
154-
return;
155-
}
156-
157-
JobStatus status = JobScheduler::ProcessJob(commands);
158-
159-
if (status == JobStatus::Error) {
160-
// Don't try to handle errors for now, but that's open to discussions.
161-
// I expect errors to be mostly OOM issues.
162-
MOZ_CRASH();
163-
}
164-
}
165-
}
166-
167157
EventObject::EventObject()
168158
: mIsSet(false)
169159
{}

gfx/2d/JobScheduler_posix.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace gfx {
2222

2323
class Job;
2424
class PosixCondVar;
25+
class WorkerThread;
2526

2627
class Mutex {
2728
public:
@@ -131,27 +132,6 @@ class MultiThreadedJobQueue {
131132
friend class WorkerThread;
132133
};
133134

134-
/// Worker thread that continuously dequeues Jobs from a MultiThreadedJobQueue
135-
/// and process them.
136-
///
137-
/// The public interface of this class must remain identical to its equivalent
138-
/// in JobScheduler_win32.h
139-
class WorkerThread {
140-
public:
141-
explicit WorkerThread(MultiThreadedJobQueue* aJobQueue);
142-
143-
~WorkerThread();
144-
145-
void Run();
146-
147-
MultiThreadedJobQueue* GetJobQueue() { return mQueue; }
148-
protected:
149-
void SetName(const char* name);
150-
151-
MultiThreadedJobQueue* mQueue;
152-
pthread_t mThread;
153-
};
154-
155135
/// An object that a thread can synchronously wait on.
156136
/// Usually set by a SetEventJob.
157137
class EventObject : public external::AtomicRefCounted<EventObject>

gfx/2d/JobScheduler_win32.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
#include "JobScheduler.h"
7+
#include "mozilla/gfx/Logging.h"
8+
9+
using namespace std;
10+
11+
namespace mozilla {
12+
namespace gfx {
13+
14+
DWORD __stdcall ThreadCallback(void* threadData);
15+
16+
class WorkerThreadWin32 : public WorkerThread {
17+
public:
18+
explicit WorkerThreadWin32(MultiThreadedJobQueue* aJobQueue)
19+
: WorkerThread(aJobQueue)
20+
{
21+
mThread = ::CreateThread(nullptr, 0, ThreadCallback, static_cast<WorkerThread*>(this), 0, nullptr);
22+
}
23+
24+
~WorkerThreadWin32()
25+
{
26+
::WaitForSingleObject(mThread, INFINITE);
27+
::CloseHandle(mThread);
28+
}
29+
30+
protected:
31+
HANDLE mThread;
32+
};
33+
34+
DWORD __stdcall ThreadCallback(void* threadData)
35+
{
36+
WorkerThread* thread = static_cast<WorkerThread*>(threadData);
37+
thread->Run();
38+
return 0;
39+
}
40+
41+
WorkerThread*
42+
WorkerThread::Create(MultiThreadedJobQueue* aJobQueue)
43+
{
44+
return new WorkerThreadWin32(aJobQueue);
45+
}
46+
47+
bool
48+
MultiThreadedJobQueue::PopJob(Job*& aOutJob, AccessType aAccess)
49+
{
50+
for (;;) {
51+
while (aAccess == BLOCKING && mJobs.empty()) {
52+
{
53+
MutexAutoLock lock(&mMutex);
54+
if (mShuttingDown) {
55+
return false;
56+
}
57+
}
58+
59+
HANDLE handles[] = { mAvailableEvent, mShutdownEvent };
60+
::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
61+
}
62+
63+
MutexAutoLock lock(&mMutex);
64+
65+
if (mShuttingDown) {
66+
return false;
67+
}
68+
69+
if (mJobs.empty()) {
70+
if (aAccess == NON_BLOCKING) {
71+
return false;
72+
}
73+
continue;
74+
}
75+
76+
Job* task = mJobs.front();
77+
MOZ_ASSERT(task);
78+
79+
mJobs.pop_front();
80+
81+
if (mJobs.empty()) {
82+
::ResetEvent(mAvailableEvent);
83+
}
84+
85+
aOutJob = task;
86+
return true;
87+
}
88+
}
89+
90+
void
91+
MultiThreadedJobQueue::SubmitJob(Job* aJob)
92+
{
93+
MOZ_ASSERT(aJob);
94+
MutexAutoLock lock(&mMutex);
95+
mJobs.push_back(aJob);
96+
::SetEvent(mAvailableEvent);
97+
}
98+
99+
void
100+
MultiThreadedJobQueue::ShutDown()
101+
{
102+
{
103+
MutexAutoLock lock(&mMutex);
104+
mShuttingDown = true;
105+
}
106+
while (mThreadsCount) {
107+
::SetEvent(mAvailableEvent);
108+
::WaitForSingleObject(mShutdownEvent, INFINITE);
109+
}
110+
}
111+
112+
size_t
113+
MultiThreadedJobQueue::NumJobs()
114+
{
115+
MutexAutoLock lock(&mMutex);
116+
return mJobs.size();
117+
}
118+
119+
bool
120+
MultiThreadedJobQueue::IsEmpty()
121+
{
122+
MutexAutoLock lock(&mMutex);
123+
return mJobs.empty();
124+
}
125+
126+
void
127+
MultiThreadedJobQueue::RegisterThread()
128+
{
129+
mThreadsCount += 1;
130+
}
131+
132+
void
133+
MultiThreadedJobQueue::UnregisterThread()
134+
{
135+
MutexAutoLock lock(&mMutex);
136+
mThreadsCount -= 1;
137+
if (mThreadsCount == 0) {
138+
::SetEvent(mShutdownEvent);
139+
}
140+
}
141+
142+
} // namespace
143+
} // namespace

0 commit comments

Comments
 (0)