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_BUILD_FOR_ANDROID) 24 return sysconf(_SC_NPROCESSORS_ONLN); 25 #else 26 return 1; 27 #endif 28 } 29 30 SkThreadPool::SkThreadPool(int count) 31 : fDone(false) { 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 fDone = true; 43 fReady.lock(); 44 fReady.broadcast(); 45 fReady.unlock(); 46 47 // Wait for all threads to stop. 48 for (int i = 0; i < fThreads.count(); i++) { 49 fThreads[i]->join(); 50 SkDELETE(fThreads[i]); 51 } 52 } 53 54 /*static*/ void SkThreadPool::Loop(void* arg) { 55 // The SkThreadPool passes itself as arg to each thread as they're created. 56 SkThreadPool* pool = static_cast<SkThreadPool*>(arg); 57 58 while (true) { 59 // We have to be holding the lock to read the queue and to call wait. 60 pool->fReady.lock(); 61 while(pool->fQueue.isEmpty()) { 62 // Is it time to die? 63 if (pool->fDone) { 64 pool->fReady.unlock(); 65 return; 66 } 67 // wait yields the lock while waiting, but will have it again when awoken. 68 pool->fReady.wait(); 69 } 70 // We've got the lock back here, no matter if we ran wait or not. 71 72 // The queue is not empty, so we have something to run. Claim it. 73 LinkedRunnable* r = pool->fQueue.tail(); 74 75 pool->fQueue.remove(r); 76 77 // Having claimed our SkRunnable, we now give up the lock while we run it. 78 // Otherwise, we'd only ever do work on one thread at a time, which rather 79 // defeats the point of this code. 80 pool->fReady.unlock(); 81 82 // OK, now really do the work. 83 r->fRunnable->run(); 84 SkDELETE(r); 85 } 86 87 SkASSERT(false); // Unreachable. The only exit happens when pool->fDone. 88 } 89 90 void SkThreadPool::add(SkRunnable* r) { 91 if (NULL == r) { 92 return; 93 } 94 95 // If we don't have any threads, obligingly just run the thing now. 96 if (fThreads.isEmpty()) { 97 return r->run(); 98 } 99 100 // We have some threads. Queue it up! 101 fReady.lock(); 102 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); 103 linkedRunnable->fRunnable = r; 104 fQueue.addToHead(linkedRunnable); 105 fReady.signal(); 106 fReady.unlock(); 107 } 108