blob: 78cb417d071b45fd08a1c9c06815c58764176d9f [file] [log] [blame]
scroggo@google.com4177ef42012-10-31 15:52:16 +00001/*
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 "SkThreadPool.h"
9#include "SkRunnable.h"
10#include "SkThreadUtils.h"
11
12SkThreadPool::SkThreadPool(const int count)
13: fDone(false) {
14 // Create count threads, all running SkThreadPool::Loop.
15 for (int i = 0; i < count; i++) {
16 SkThread* thread = SkNEW_ARGS(SkThread, (&SkThreadPool::Loop, this));
17 *fThreads.append() = thread;
18 thread->start();
19 }
20}
21
22SkThreadPool::~SkThreadPool() {
23 fDone = true;
24 fReady.lock();
25 fReady.broadcast();
26 fReady.unlock();
27
28 // Wait for all threads to stop.
29 for (int i = 0; i < fThreads.count(); i++) {
30 fThreads[i]->join();
31 SkDELETE(fThreads[i]);
32 }
33}
34
35/*static*/ void SkThreadPool::Loop(void* arg) {
36 // The SkThreadPool passes itself as arg to each thread as they're created.
37 SkThreadPool* pool = static_cast<SkThreadPool*>(arg);
38
39 while (true) {
40 // We have to be holding the lock to read the queue and to call wait.
41 pool->fReady.lock();
42 while(pool->fQueue.isEmpty()) {
43 // Is it time to die?
44 if (pool->fDone) {
45 pool->fReady.unlock();
46 return;
47 }
48 // wait yields the lock while waiting, but will have it again when awoken.
49 pool->fReady.wait();
50 }
51 // We've got the lock back here, no matter if we ran wait or not.
52
53 // The queue is not empty, so we have something to run. Claim it.
54 LinkedRunnable* r = pool->fQueue.tail();
55
56 pool->fQueue.remove(r);
57
58 // Having claimed our SkRunnable, we now give up the lock while we run it.
59 // Otherwise, we'd only ever do work on one thread at a time, which rather
60 // defeats the point of this code.
61 pool->fReady.unlock();
62
63 // OK, now really do the work.
64 r->fRunnable->run();
65 SkDELETE(r);
66 }
67
68 SkASSERT(false); // Unreachable. The only exit happens when pool->fDone.
69}
70
71void SkThreadPool::add(SkRunnable* r) {
72 if (NULL == r) {
73 return;
74 }
75
76 // If we don't have any threads, obligingly just run the thing now.
77 if (fThreads.isEmpty()) {
78 return r->run();
79 }
80
81 // We have some threads. Queue it up!
82 fReady.lock();
83 LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable);
84 linkedRunnable->fRunnable = r;
85 fQueue.addToHead(linkedRunnable);
86 fReady.signal();
87 fReady.unlock();
88}