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