OLD | NEW |
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 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 ~SkTThreadPool(); | 43 ~SkTThreadPool(); |
44 | 44 |
45 /** | 45 /** |
46 * Queues up an SkRunnable to run when a thread is available, or synchronous
ly if count is 0. | 46 * Queues up an SkRunnable to run when a thread is available, or synchronous
ly if count is 0. |
47 * Does not take ownership. NULL is a safe no-op. If T is not void, the run
nable will be passed | 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. | 48 * a reference to a T on the thread's local stack. |
49 */ | 49 */ |
50 void add(SkTRunnable<T>*); | 50 void add(SkTRunnable<T>*); |
51 | 51 |
52 /** | 52 /** |
| 53 * Same as add, but adds the runnable as the very next to run rather than en
queueing it. |
| 54 */ |
| 55 void addNext(SkTRunnable<T>*); |
| 56 |
| 57 /** |
53 * Block until all added SkRunnables have completed. Once called, calling a
dd() is undefined. | 58 * Block until all added SkRunnables have completed. Once called, calling a
dd() is undefined. |
54 */ | 59 */ |
55 void wait(); | 60 void wait(); |
56 | 61 |
57 private: | 62 private: |
58 struct LinkedRunnable { | 63 struct LinkedRunnable { |
59 SkTRunnable<T>* fRunnable; // Unowned. | 64 SkTRunnable<T>* fRunnable; // Unowned. |
60 SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable); | 65 SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable); |
61 }; | 66 }; |
62 | 67 |
63 enum State { | 68 enum State { |
64 kRunning_State, // Normal case. We've been constructed and no one has
called wait(). | 69 kRunning_State, // Normal case. We've been constructed and no one has
called wait(). |
65 kWaiting_State, // wait has been called, but there still might be work
to do or being done. | 70 kWaiting_State, // wait has been called, but there still might be work
to do or being done. |
66 kHalting_State, // There's no work to do and no thread is busy. All th
reads can shut down. | 71 kHalting_State, // There's no work to do and no thread is busy. All th
reads can shut down. |
67 }; | 72 }; |
68 | 73 |
| 74 void addSomewhere(SkTRunnable<T>* r, |
| 75 void (SkTInternalLList<LinkedRunnable>::*)(LinkedRunnable*
)); |
| 76 |
69 SkTInternalLList<LinkedRunnable> fQueue; | 77 SkTInternalLList<LinkedRunnable> fQueue; |
70 SkCondVar fReady; | 78 SkCondVar fReady; |
71 SkTDArray<SkThread*> fThreads; | 79 SkTDArray<SkThread*> fThreads; |
72 State fState; | 80 State fState; |
73 int fBusyThreads; | 81 int fBusyThreads; |
74 | 82 |
75 static void Loop(void*); // Static because we pass in this. | 83 static void Loop(void*); // Static because we pass in this. |
76 }; | 84 }; |
77 | 85 |
78 template <typename T> | 86 template <typename T> |
(...skipping 25 matching lines...) Expand all Loading... |
104 }; | 112 }; |
105 | 113 |
106 template <> | 114 template <> |
107 struct ThreadLocal<void> { | 115 struct ThreadLocal<void> { |
108 void run(SkTRunnable<void>* r) { r->run(); } | 116 void run(SkTRunnable<void>* r) { r->run(); } |
109 }; | 117 }; |
110 | 118 |
111 } // namespace SkThreadPoolPrivate | 119 } // namespace SkThreadPoolPrivate |
112 | 120 |
113 template <typename T> | 121 template <typename T> |
114 void SkTThreadPool<T>::add(SkTRunnable<T>* r) { | 122 void SkTThreadPool<T>::addSomewhere(SkTRunnable<T>* r, |
| 123 void (SkTInternalLList<LinkedRunnable>::* f)
(LinkedRunnable*)) { |
115 if (r == NULL) { | 124 if (r == NULL) { |
116 return; | 125 return; |
117 } | 126 } |
118 | 127 |
119 if (fThreads.isEmpty()) { | 128 if (fThreads.isEmpty()) { |
120 SkThreadPoolPrivate::ThreadLocal<T> threadLocal; | 129 SkThreadPoolPrivate::ThreadLocal<T> threadLocal; |
121 threadLocal.run(r); | 130 threadLocal.run(r); |
122 return; | 131 return; |
123 } | 132 } |
124 | 133 |
125 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); | 134 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); |
126 linkedRunnable->fRunnable = r; | 135 linkedRunnable->fRunnable = r; |
127 fReady.lock(); | 136 fReady.lock(); |
128 SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when w
e're halting. | 137 SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when w
e're halting. |
129 fQueue.addToHead(linkedRunnable); | 138 (fQueue.*f)(linkedRunnable); |
130 fReady.signal(); | 139 fReady.signal(); |
131 fReady.unlock(); | 140 fReady.unlock(); |
132 } | 141 } |
133 | 142 |
| 143 template <typename T> |
| 144 void SkTThreadPool<T>::add(SkTRunnable<T>* r) { |
| 145 this->addSomewhere(r, &SkTInternalLList<LinkedRunnable>::addToTail); |
| 146 } |
| 147 |
| 148 template <typename T> |
| 149 void SkTThreadPool<T>::addNext(SkTRunnable<T>* r) { |
| 150 this->addSomewhere(r, &SkTInternalLList<LinkedRunnable>::addToHead); |
| 151 } |
| 152 |
134 | 153 |
135 template <typename T> | 154 template <typename T> |
136 void SkTThreadPool<T>::wait() { | 155 void SkTThreadPool<T>::wait() { |
137 fReady.lock(); | 156 fReady.lock(); |
138 fState = kWaiting_State; | 157 fState = kWaiting_State; |
139 fReady.broadcast(); | 158 fReady.broadcast(); |
140 fReady.unlock(); | 159 fReady.unlock(); |
141 | 160 |
142 // Wait for all threads to stop. | 161 // Wait for all threads to stop. |
143 for (int i = 0; i < fThreads.count(); i++) { | 162 for (int i = 0; i < fThreads.count(); i++) { |
(...skipping 23 matching lines...) Expand all Loading... |
167 if (kHalting_State == pool->fState) { | 186 if (kHalting_State == pool->fState) { |
168 pool->fReady.unlock(); | 187 pool->fReady.unlock(); |
169 return; | 188 return; |
170 } | 189 } |
171 // wait yields the lock while waiting, but will have it again when a
woken. | 190 // wait yields the lock while waiting, but will have it again when a
woken. |
172 pool->fReady.wait(); | 191 pool->fReady.wait(); |
173 } | 192 } |
174 // We've got the lock back here, no matter if we ran wait or not. | 193 // We've got the lock back here, no matter if we ran wait or not. |
175 | 194 |
176 // The queue is not empty, so we have something to run. Claim it. | 195 // The queue is not empty, so we have something to run. Claim it. |
177 LinkedRunnable* r = pool->fQueue.tail(); | 196 LinkedRunnable* r = pool->fQueue.head(); |
178 | 197 |
179 pool->fQueue.remove(r); | 198 pool->fQueue.remove(r); |
180 | 199 |
181 // Having claimed our SkRunnable, we now give up the lock while we run i
t. | 200 // 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 | 201 // Otherwise, we'd only ever do work on one thread at a time, which rath
er |
183 // defeats the point of this code. | 202 // defeats the point of this code. |
184 pool->fBusyThreads++; | 203 pool->fBusyThreads++; |
185 pool->fReady.unlock(); | 204 pool->fReady.unlock(); |
186 | 205 |
187 // OK, now really do the work. | 206 // OK, now really do the work. |
188 threadLocal.run(r->fRunnable); | 207 threadLocal.run(r->fRunnable); |
189 SkDELETE(r); | 208 SkDELETE(r); |
190 | 209 |
191 // Let everyone know we're not busy. | 210 // Let everyone know we're not busy. |
192 pool->fReady.lock(); | 211 pool->fReady.lock(); |
193 pool->fBusyThreads--; | 212 pool->fBusyThreads--; |
194 pool->fReady.unlock(); | 213 pool->fReady.unlock(); |
195 } | 214 } |
196 | 215 |
197 SkASSERT(false); // Unreachable. The only exit happens when pool->fState is
kHalting_State. | 216 SkASSERT(false); // Unreachable. The only exit happens when pool->fState is
kHalting_State. |
198 } | 217 } |
199 | 218 |
200 typedef SkTThreadPool<void> SkThreadPool; | 219 typedef SkTThreadPool<void> SkThreadPool; |
201 | 220 |
202 #endif | 221 #endif |
OLD | NEW |