Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: include/utils/SkThreadPool.h

Issue 179233005: DM: make GPU tasks multithreaded again. Big refactor. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: default 1 GPU thread Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/utils/SkRunnable.h ('k') | src/utils/SkThreadPool.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #ifndef SkThreadPool_DEFINED 8 #ifndef SkThreadPool_DEFINED
9 #define SkThreadPool_DEFINED 9 #define SkThreadPool_DEFINED
10 10
11 #include "SkCondVar.h" 11 #include "SkCondVar.h"
12 #include "SkRunnable.h" 12 #include "SkRunnable.h"
13 #include "SkTDArray.h" 13 #include "SkTDArray.h"
14 #include "SkTInternalLList.h" 14 #include "SkTInternalLList.h"
15 #include "SkThreadUtils.h"
16 #include "SkTypes.h"
15 17
16 class SkThread; 18 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_ FOR_ANDROID)
19 # include <unistd.h>
20 #endif
17 21
18 class SkThreadPool { 22 // Returns the number of cores on this machine.
23 static inline int num_cores() {
24 #if defined(SK_BUILD_FOR_WIN32)
25 SYSTEM_INFO sysinfo;
26 GetSystemInfo(&sysinfo);
27 return sysinfo.dwNumberOfProcessors;
28 #elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUIL D_FOR_ANDROID)
29 return sysconf(_SC_NPROCESSORS_ONLN);
30 #else
31 return 1;
32 #endif
33 }
19 34
35 template <typename T>
36 class SkTThreadPool {
20 public: 37 public:
21 /** 38 /**
22 * Create a threadpool with count threads, or one thread per core if kThread PerCore. 39 * Create a threadpool with count threads, or one thread per core if kThread PerCore.
23 */ 40 */
24 static const int kThreadPerCore = -1; 41 static const int kThreadPerCore = -1;
25 explicit SkThreadPool(int count); 42 explicit SkTThreadPool(int count);
26 ~SkThreadPool(); 43 ~SkTThreadPool();
27 44
28 /** 45 /**
29 * Queues up an SkRunnable to run when a thread is available, or immediately if 46 * Queues up an SkRunnable to run when a thread is available, or synchronous ly if count is 0.
30 * count is 0. NULL is a safe no-op. Does not take ownership. 47 * Does not take ownership. NULL is a safe no-op. If T is not void, the run nable will be passed
48 * a reference to a T on the thread's local stack.
31 */ 49 */
32 void add(SkRunnable*); 50 void add(SkTRunnable<T>*);
33 51
34 /** 52 /**
35 * Block until all added SkRunnables have completed. Once called, calling a dd() is undefined. 53 * Block until all added SkRunnables have completed. Once called, calling a dd() is undefined.
36 */ 54 */
37 void wait(); 55 void wait();
38 56
39 private: 57 private:
40 struct LinkedRunnable { 58 struct LinkedRunnable {
41 // Unowned pointer. 59 SkTRunnable<T>* fRunnable; // Unowned.
42 SkRunnable* fRunnable;
43
44 private:
45 SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable); 60 SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable);
46 }; 61 };
47 62
48 enum State { 63 enum State {
49 kRunning_State, // Normal case. We've been constructed and no one has called wait(). 64 kRunning_State, // Normal case. We've been constructed and no one has called wait().
50 kWaiting_State, // wait has been called, but there still might be work to do or being done. 65 kWaiting_State, // wait has been called, but there still might be work to do or being done.
51 kHalting_State, // There's no work to do and no thread is busy. All th reads can shut down. 66 kHalting_State, // There's no work to do and no thread is busy. All th reads can shut down.
52 }; 67 };
53 68
54 SkTInternalLList<LinkedRunnable> fQueue; 69 SkTInternalLList<LinkedRunnable> fQueue;
55 SkCondVar fReady; 70 SkCondVar fReady;
56 SkTDArray<SkThread*> fThreads; 71 SkTDArray<SkThread*> fThreads;
57 State fState; 72 State fState;
58 int fBusyThreads; 73 int fBusyThreads;
59 74
60 static void Loop(void*); // Static because we pass in this. 75 static void Loop(void*); // Static because we pass in this.
61 }; 76 };
62 77
78 template <typename T>
79 SkTThreadPool<T>::SkTThreadPool(int count) : fState(kRunning_State), fBusyThread s(0) {
80 if (count < 0) {
81 count = num_cores();
82 }
83 // Create count threads, all running SkTThreadPool::Loop.
84 for (int i = 0; i < count; i++) {
85 SkThread* thread = SkNEW_ARGS(SkThread, (&SkTThreadPool::Loop, this));
86 *fThreads.append() = thread;
87 thread->start();
88 }
89 }
90
91 template <typename T>
92 SkTThreadPool<T>::~SkTThreadPool() {
93 if (kRunning_State == fState) {
94 this->wait();
95 }
96 }
97
98 namespace SkThreadPoolPrivate {
99
100 template <typename T>
101 struct ThreadLocal {
102 void run(SkTRunnable<T>* r) { r->run(data); }
103 T data;
104 };
105
106 template <>
107 struct ThreadLocal<void> {
108 void run(SkTRunnable<void>* r) { r->run(); }
109 };
110
111 } // namespace SkThreadPoolPrivate
112
113 template <typename T>
114 void SkTThreadPool<T>::add(SkTRunnable<T>* r) {
115 if (r == NULL) {
116 return;
117 }
118
119 if (fThreads.isEmpty()) {
120 SkThreadPoolPrivate::ThreadLocal<T> threadLocal;
121 threadLocal.run(r);
122 return;
123 }
124
125 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable);
126 linkedRunnable->fRunnable = r;
127 fReady.lock();
128 SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when w e're halting.
129 fQueue.addToHead(linkedRunnable);
130 fReady.signal();
131 fReady.unlock();
132 }
133
134
135 template <typename T>
136 void SkTThreadPool<T>::wait() {
137 fReady.lock();
138 fState = kWaiting_State;
139 fReady.broadcast();
140 fReady.unlock();
141
142 // Wait for all threads to stop.
143 for (int i = 0; i < fThreads.count(); i++) {
144 fThreads[i]->join();
145 SkDELETE(fThreads[i]);
146 }
147 SkASSERT(fQueue.isEmpty());
148 }
149
150 template <typename T>
151 /*static*/ void SkTThreadPool<T>::Loop(void* arg) {
152 // The SkTThreadPool passes itself as arg to each thread as they're created.
153 SkTThreadPool<T>* pool = static_cast<SkTThreadPool<T>*>(arg);
154 SkThreadPoolPrivate::ThreadLocal<T> threadLocal;
155
156 while (true) {
157 // We have to be holding the lock to read the queue and to call wait.
158 pool->fReady.lock();
159 while(pool->fQueue.isEmpty()) {
160 // Does the client want to stop and are all the threads ready to sto p?
161 // If so, we move into the halting state, and whack all the threads so they notice.
162 if (kWaiting_State == pool->fState && pool->fBusyThreads == 0) {
163 pool->fState = kHalting_State;
164 pool->fReady.broadcast();
165 }
166 // Any time we find ourselves in the halting state, it's quitting ti me.
167 if (kHalting_State == pool->fState) {
168 pool->fReady.unlock();
169 return;
170 }
171 // wait yields the lock while waiting, but will have it again when a woken.
172 pool->fReady.wait();
173 }
174 // We've got the lock back here, no matter if we ran wait or not.
175
176 // The queue is not empty, so we have something to run. Claim it.
177 LinkedRunnable* r = pool->fQueue.tail();
178
179 pool->fQueue.remove(r);
180
181 // Having claimed our SkRunnable, we now give up the lock while we run i t.
182 // Otherwise, we'd only ever do work on one thread at a time, which rath er
183 // defeats the point of this code.
184 pool->fBusyThreads++;
185 pool->fReady.unlock();
186
187 // OK, now really do the work.
188 threadLocal.run(r->fRunnable);
189 SkDELETE(r);
190
191 // Let everyone know we're not busy.
192 pool->fReady.lock();
193 pool->fBusyThreads--;
194 pool->fReady.unlock();
195 }
196
197 SkASSERT(false); // Unreachable. The only exit happens when pool->fState is kHalting_State.
198 }
199
200 typedef SkTThreadPool<void> SkThreadPool;
201
63 #endif 202 #endif
OLDNEW
« no previous file with comments | « include/utils/SkRunnable.h ('k') | src/utils/SkThreadPool.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698