1363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/* 2363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Copyright 2012 Google Inc. 3363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * 4363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be 5363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * found in the LICENSE file. 6363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */ 7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkRunnable.h" 97839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "SkThreadPool.h" 10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkThreadUtils.h" 117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "SkTypes.h" 127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger 137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_ANDROID) 147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include <unistd.h> 157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#endif 167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger 177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger// Returns the number of cores on this machine. 187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerstatic int num_cores() { 197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#if defined(SK_BUILD_FOR_WIN32) 207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger SYSTEM_INFO sysinfo; 217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger GetSystemInfo(&sysinfo); 227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return sysinfo.dwNumberOfProcessors; 237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_ANDROID) 247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return sysconf(_SC_NPROCESSORS_ONLN); 257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#else 267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return 1; 277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#endif 287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger} 29363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerSkThreadPool::SkThreadPool(int count) 31363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger: fDone(false) { 327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger if (count < 0) count = num_cores(); 33363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Create count threads, all running SkThreadPool::Loop. 34363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < count; i++) { 35363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkThread* thread = SkNEW_ARGS(SkThread, (&SkThreadPool::Loop, this)); 36363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *fThreads.append() = thread; 37363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger thread->start(); 38363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 39363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 41363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerSkThreadPool::~SkThreadPool() { 42363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fDone = true; 43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.lock(); 44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.broadcast(); 45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.unlock(); 46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 47363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Wait for all threads to stop. 48363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < fThreads.count(); i++) { 49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fThreads[i]->join(); 50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDELETE(fThreads[i]); 51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*static*/ void SkThreadPool::Loop(void* arg) { 55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // The SkThreadPool passes itself as arg to each thread as they're created. 56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkThreadPool* pool = static_cast<SkThreadPool*>(arg); 57363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 58363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger while (true) { 59363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // We have to be holding the lock to read the queue and to call wait. 60363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger pool->fReady.lock(); 61363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger while(pool->fQueue.isEmpty()) { 62363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Is it time to die? 63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (pool->fDone) { 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger pool->fReady.unlock(); 65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // wait yields the lock while waiting, but will have it again when awoken. 68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger pool->fReady.wait(); 69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // We've got the lock back here, no matter if we ran wait or not. 71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // The queue is not empty, so we have something to run. Claim it. 73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger LinkedRunnable* r = pool->fQueue.tail(); 74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger pool->fQueue.remove(r); 76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Having claimed our SkRunnable, we now give up the lock while we run it. 78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Otherwise, we'd only ever do work on one thread at a time, which rather 79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // defeats the point of this code. 80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger pool->fReady.unlock(); 81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // OK, now really do the work. 83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger r->fRunnable->run(); 84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDELETE(r); 85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(false); // Unreachable. The only exit happens when pool->fDone. 88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkThreadPool::add(SkRunnable* r) { 91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL == r) { 92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // If we don't have any threads, obligingly just run the thing now. 96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fThreads.isEmpty()) { 97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return r->run(); 98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // We have some threads. Queue it up! 101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.lock(); 102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable); 103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger linkedRunnable->fRunnable = r; 104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fQueue.addToHead(linkedRunnable); 105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.signal(); 106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fReady.unlock(); 107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 108