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