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 void* ThreadCallback(void* threadData);
15
16 class WorkerThreadPosix : public WorkerThread {
17 public:
WorkerThreadPosix(MultiThreadedJobQueue * aJobQueue)18 explicit WorkerThreadPosix(MultiThreadedJobQueue* aJobQueue)
19 : WorkerThread(aJobQueue)
20 {
21 pthread_create(&mThread, nullptr, ThreadCallback, static_cast<WorkerThread*>(this));
22 }
23
~WorkerThreadPosix()24 ~WorkerThreadPosix()
25 {
26 pthread_join(mThread, nullptr);
27 }
28
SetName(const char *)29 virtual void SetName(const char*) override
30 {
31 // XXX - temporarily disabled, see bug 1209039
32 //
33 // // Call this from the thread itself because of Mac.
34 //#ifdef XP_MACOSX
35 // pthread_setname_np(aName);
36 //#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
37 // pthread_set_name_np(mThread, aName);
38 //#elif defined(__NetBSD__)
39 // pthread_setname_np(mThread, "%s", (void*)aName);
40 //#else
41 // pthread_setname_np(mThread, aName);
42 //#endif
43 }
44
45 protected:
46 pthread_t mThread;
47 };
48
ThreadCallback(void * threadData)49 void* ThreadCallback(void* threadData)
50 {
51 WorkerThread* thread = static_cast<WorkerThread*>(threadData);
52 thread->Run();
53 return nullptr;
54 }
55
56 WorkerThread*
Create(MultiThreadedJobQueue * aJobQueue)57 WorkerThread::Create(MultiThreadedJobQueue* aJobQueue)
58 {
59 return new WorkerThreadPosix(aJobQueue);
60 }
61
MultiThreadedJobQueue()62 MultiThreadedJobQueue::MultiThreadedJobQueue()
63 : mThreadsCount(0)
64 , mShuttingDown(false)
65 {}
66
~MultiThreadedJobQueue()67 MultiThreadedJobQueue::~MultiThreadedJobQueue()
68 {
69 MOZ_ASSERT(mJobs.empty());
70 }
71
72 bool
WaitForJob(Job * & aOutJob)73 MultiThreadedJobQueue::WaitForJob(Job*& aOutJob)
74 {
75 return PopJob(aOutJob, BLOCKING);
76 }
77
78 bool
PopJob(Job * & aOutJobs,AccessType aAccess)79 MultiThreadedJobQueue::PopJob(Job*& aOutJobs, AccessType aAccess)
80 {
81 for (;;) {
82 CriticalSectionAutoEnter lock(&mMutex);
83
84 while (aAccess == BLOCKING && !mShuttingDown && mJobs.empty()) {
85 mAvailableCondvar.Wait(&mMutex);
86 }
87
88 if (mShuttingDown) {
89 return false;
90 }
91
92 if (mJobs.empty()) {
93 if (aAccess == NON_BLOCKING) {
94 return false;
95 }
96 continue;
97 }
98
99 Job* task = mJobs.front();
100 MOZ_ASSERT(task);
101
102 mJobs.pop_front();
103
104 aOutJobs = task;
105 return true;
106 }
107 }
108
109 void
SubmitJob(Job * aJobs)110 MultiThreadedJobQueue::SubmitJob(Job* aJobs)
111 {
112 MOZ_ASSERT(aJobs);
113 CriticalSectionAutoEnter lock(&mMutex);
114 mJobs.push_back(aJobs);
115 mAvailableCondvar.Broadcast();
116 }
117
118 size_t
NumJobs()119 MultiThreadedJobQueue::NumJobs()
120 {
121 CriticalSectionAutoEnter lock(&mMutex);
122 return mJobs.size();
123 }
124
125 bool
IsEmpty()126 MultiThreadedJobQueue::IsEmpty()
127 {
128 CriticalSectionAutoEnter lock(&mMutex);
129 return mJobs.empty();
130 }
131
132 void
ShutDown()133 MultiThreadedJobQueue::ShutDown()
134 {
135 CriticalSectionAutoEnter lock(&mMutex);
136 mShuttingDown = true;
137 while (mThreadsCount) {
138 mAvailableCondvar.Broadcast();
139 mShutdownCondvar.Wait(&mMutex);
140 }
141 }
142
143 void
RegisterThread()144 MultiThreadedJobQueue::RegisterThread()
145 {
146 mThreadsCount += 1;
147 }
148
149 void
UnregisterThread()150 MultiThreadedJobQueue::UnregisterThread()
151 {
152 CriticalSectionAutoEnter lock(&mMutex);
153 mThreadsCount -= 1;
154 if (mThreadsCount == 0) {
155 mShutdownCondvar.Broadcast();
156 }
157 }
158
EventObject()159 EventObject::EventObject()
160 : mIsSet(false)
161 {}
162
~EventObject()163 EventObject::~EventObject()
164 {}
165
166 bool
Peak()167 EventObject::Peak()
168 {
169 CriticalSectionAutoEnter lock(&mMutex);
170 return mIsSet;
171 }
172
173 void
Set()174 EventObject::Set()
175 {
176 CriticalSectionAutoEnter lock(&mMutex);
177 if (!mIsSet) {
178 mIsSet = true;
179 mCond.Broadcast();
180 }
181 }
182
183 void
Wait()184 EventObject::Wait()
185 {
186 CriticalSectionAutoEnter lock(&mMutex);
187 if (mIsSet) {
188 return;
189 }
190 mCond.Wait(&mMutex);
191 }
192
193 } // namespce
194 } // namespce
195