Index: src/utils/SkThreadPool.cpp |
diff --git a/src/utils/SkThreadPool.cpp b/src/utils/SkThreadPool.cpp |
index e078af3ba3e914add1428460b66c24f6dafe9bb6..125a5d9b6ad78674e057af791b8859e7159bd36e 100644 |
--- a/src/utils/SkThreadPool.cpp |
+++ b/src/utils/SkThreadPool.cpp |
@@ -28,7 +28,7 @@ static int num_cores() { |
} |
SkThreadPool::SkThreadPool(int count) |
-: fDone(false) { |
+: fState(kRunning_State), fBusyThreads(0) { |
if (count < 0) count = num_cores(); |
// Create count threads, all running SkThreadPool::Loop. |
for (int i = 0; i < count; i++) { |
@@ -39,14 +39,14 @@ SkThreadPool::SkThreadPool(int count) |
} |
SkThreadPool::~SkThreadPool() { |
- if (!fDone) { |
+ if (kRunning_State == fState) { |
this->wait(); |
} |
} |
void SkThreadPool::wait() { |
fReady.lock(); |
- fDone = true; |
+ fState = kWaiting_State; |
fReady.broadcast(); |
fReady.unlock(); |
@@ -55,6 +55,7 @@ void SkThreadPool::wait() { |
fThreads[i]->join(); |
SkDELETE(fThreads[i]); |
} |
+ SkASSERT(fQueue.isEmpty()); |
} |
/*static*/ void SkThreadPool::Loop(void* arg) { |
@@ -65,8 +66,14 @@ void SkThreadPool::wait() { |
// We have to be holding the lock to read the queue and to call wait. |
pool->fReady.lock(); |
while(pool->fQueue.isEmpty()) { |
- // Is it time to die? |
- if (pool->fDone) { |
+ // Does the client want to stop and are all the threads ready to stop? |
+ // If so, we move into the halting state, and whack all the threads so they notice. |
+ if (kWaiting_State == pool->fState && pool->fBusyThreads == 0) { |
+ pool->fState = kHalting_State; |
+ pool->fReady.broadcast(); |
+ } |
+ // Any time we find ourselves in the halting state, it's quitting time. |
+ if (kHalting_State == pool->fState) { |
pool->fReady.unlock(); |
return; |
} |
@@ -83,14 +90,20 @@ void SkThreadPool::wait() { |
// Having claimed our SkRunnable, we now give up the lock while we run it. |
// Otherwise, we'd only ever do work on one thread at a time, which rather |
// defeats the point of this code. |
+ pool->fBusyThreads++; |
pool->fReady.unlock(); |
// OK, now really do the work. |
r->fRunnable->run(); |
SkDELETE(r); |
+ |
+ // Let everyone know we're not busy. |
+ pool->fReady.lock(); |
+ pool->fBusyThreads--; |
+ pool->fReady.unlock(); |
} |
- SkASSERT(false); // Unreachable. The only exit happens when pool->fDone. |
+ SkASSERT(false); // Unreachable. The only exit happens when pool->fState is kHalting_State. |
} |
void SkThreadPool::add(SkRunnable* r) { |
@@ -105,7 +118,7 @@ void SkThreadPool::add(SkRunnable* r) { |
// We have some threads. Queue it up! |
fReady.lock(); |
- SkASSERT(!fDone); // We shouldn't be adding work to a pool that's shut down. |
+ SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when we're halting. |
LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); |
linkedRunnable->fRunnable = r; |
fQueue.addToHead(linkedRunnable); |