| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2012 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "SkRunnable.h" | |
| 9 #include "SkThreadPool.h" | |
| 10 #include "SkThreadUtils.h" | |
| 11 #include "SkTypes.h" | |
| 12 | |
| 13 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_
FOR_ANDROID) | |
| 14 #include <unistd.h> | |
| 15 #endif | |
| 16 | |
| 17 // Returns the number of cores on this machine. | |
| 18 static int num_cores() { | |
| 19 #if defined(SK_BUILD_FOR_WIN32) | |
| 20 SYSTEM_INFO sysinfo; | |
| 21 GetSystemInfo(&sysinfo); | |
| 22 return sysinfo.dwNumberOfProcessors; | |
| 23 #elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUIL
D_FOR_ANDROID) | |
| 24 return sysconf(_SC_NPROCESSORS_ONLN); | |
| 25 #else | |
| 26 return 1; | |
| 27 #endif | |
| 28 } | |
| 29 | |
| 30 SkThreadPool::SkThreadPool(int count) | |
| 31 : fState(kRunning_State), fBusyThreads(0) { | |
| 32 if (count < 0) count = num_cores(); | |
| 33 // Create count threads, all running SkThreadPool::Loop. | |
| 34 for (int i = 0; i < count; i++) { | |
| 35 SkThread* thread = SkNEW_ARGS(SkThread, (&SkThreadPool::Loop, this)); | |
| 36 *fThreads.append() = thread; | |
| 37 thread->start(); | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 SkThreadPool::~SkThreadPool() { | |
| 42 if (kRunning_State == fState) { | |
| 43 this->wait(); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 void SkThreadPool::wait() { | |
| 48 fReady.lock(); | |
| 49 fState = kWaiting_State; | |
| 50 fReady.broadcast(); | |
| 51 fReady.unlock(); | |
| 52 | |
| 53 // Wait for all threads to stop. | |
| 54 for (int i = 0; i < fThreads.count(); i++) { | |
| 55 fThreads[i]->join(); | |
| 56 SkDELETE(fThreads[i]); | |
| 57 } | |
| 58 SkASSERT(fQueue.isEmpty()); | |
| 59 } | |
| 60 | |
| 61 /*static*/ void SkThreadPool::Loop(void* arg) { | |
| 62 // The SkThreadPool passes itself as arg to each thread as they're created. | |
| 63 SkThreadPool* pool = static_cast<SkThreadPool*>(arg); | |
| 64 | |
| 65 while (true) { | |
| 66 // We have to be holding the lock to read the queue and to call wait. | |
| 67 pool->fReady.lock(); | |
| 68 while(pool->fQueue.isEmpty()) { | |
| 69 // Does the client want to stop and are all the threads ready to sto
p? | |
| 70 // If so, we move into the halting state, and whack all the threads
so they notice. | |
| 71 if (kWaiting_State == pool->fState && pool->fBusyThreads == 0) { | |
| 72 pool->fState = kHalting_State; | |
| 73 pool->fReady.broadcast(); | |
| 74 } | |
| 75 // Any time we find ourselves in the halting state, it's quitting ti
me. | |
| 76 if (kHalting_State == pool->fState) { | |
| 77 pool->fReady.unlock(); | |
| 78 return; | |
| 79 } | |
| 80 // wait yields the lock while waiting, but will have it again when a
woken. | |
| 81 pool->fReady.wait(); | |
| 82 } | |
| 83 // We've got the lock back here, no matter if we ran wait or not. | |
| 84 | |
| 85 // The queue is not empty, so we have something to run. Claim it. | |
| 86 LinkedRunnable* r = pool->fQueue.tail(); | |
| 87 | |
| 88 pool->fQueue.remove(r); | |
| 89 | |
| 90 // Having claimed our SkRunnable, we now give up the lock while we run i
t. | |
| 91 // Otherwise, we'd only ever do work on one thread at a time, which rath
er | |
| 92 // defeats the point of this code. | |
| 93 pool->fBusyThreads++; | |
| 94 pool->fReady.unlock(); | |
| 95 | |
| 96 // OK, now really do the work. | |
| 97 r->fRunnable->run(); | |
| 98 SkDELETE(r); | |
| 99 | |
| 100 // Let everyone know we're not busy. | |
| 101 pool->fReady.lock(); | |
| 102 pool->fBusyThreads--; | |
| 103 pool->fReady.unlock(); | |
| 104 } | |
| 105 | |
| 106 SkASSERT(false); // Unreachable. The only exit happens when pool->fState is
kHalting_State. | |
| 107 } | |
| 108 | |
| 109 void SkThreadPool::add(SkRunnable* r) { | |
| 110 if (NULL == r) { | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 // If we don't have any threads, obligingly just run the thing now. | |
| 115 if (fThreads.isEmpty()) { | |
| 116 return r->run(); | |
| 117 } | |
| 118 | |
| 119 // We have some threads. Queue it up! | |
| 120 fReady.lock(); | |
| 121 SkASSERT(fState != kHalting_State); // Shouldn't be able to add work when w
e're halting. | |
| 122 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); | |
| 123 linkedRunnable->fRunnable = r; | |
| 124 fQueue.addToHead(linkedRunnable); | |
| 125 fReady.signal(); | |
| 126 fReady.unlock(); | |
| 127 } | |
| OLD | NEW |