aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-10-31 15:52:16 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-10-31 15:52:16 +0000
commit4177ef4b229b5fb67f355569654981bb4bf8eb9c (patch)
tree0091c5ff6ed7dd7b89e73f9b11cde51e700c5726 /src
parent72ba668db833d25ecdca4edfbefd601e508a1e62 (diff)
Add SkThreadPool for managing threads.
Skia-ized from https://codereview.appspot.com/6755043/ TODO: Use SkThread and platform independent features. Review URL: https://codereview.appspot.com/6777064 git-svn-id: http://skia.googlecode.com/svn/trunk@6217 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/utils/SkCondVar.cpp38
-rw-r--r--src/utils/SkCountdown.cpp33
-rw-r--r--src/utils/SkThreadPool.cpp88
3 files changed, 159 insertions, 0 deletions
diff --git a/src/utils/SkCondVar.cpp b/src/utils/SkCondVar.cpp
new file mode 100644
index 0000000000..8cbab58de2
--- /dev/null
+++ b/src/utils/SkCondVar.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCondVar.h"
+
+SkCondVar::SkCondVar() {
+ pthread_mutex_init(&fMutex, NULL /* default mutex attr */);
+ pthread_cond_init(&fCond, NULL /* default cond attr */);
+}
+
+SkCondVar::~SkCondVar() {
+ pthread_mutex_destroy(&fMutex);
+ pthread_cond_destroy(&fCond);
+}
+
+void SkCondVar::lock() {
+ pthread_mutex_lock(&fMutex);
+}
+
+void SkCondVar::unlock() {
+ pthread_mutex_unlock(&fMutex);
+}
+
+void SkCondVar::wait() {
+ pthread_cond_wait(&fCond, &fMutex);
+}
+
+void SkCondVar::signal() {
+ pthread_cond_signal(&fCond);
+}
+
+void SkCondVar::broadcast() {
+ pthread_cond_broadcast(&fCond);
+}
diff --git a/src/utils/SkCountdown.cpp b/src/utils/SkCountdown.cpp
new file mode 100644
index 0000000000..5b476cc094
--- /dev/null
+++ b/src/utils/SkCountdown.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCountdown.h"
+#include "SkThread.h"
+
+SkCountdown::SkCountdown(int32_t count)
+: fCount(count) {}
+
+void SkCountdown::reset(int32_t count) {
+ fCount = count;
+}
+
+void SkCountdown::run() {
+ if (sk_atomic_dec(&fCount) == 1) {
+ fReady.lock();
+ fReady.signal();
+ fReady.unlock();
+ }
+}
+
+void SkCountdown::wait() {
+ fReady.lock();
+ while (fCount > 0) {
+ fReady.wait();
+ }
+ fReady.unlock();
+}
+
diff --git a/src/utils/SkThreadPool.cpp b/src/utils/SkThreadPool.cpp
new file mode 100644
index 0000000000..78cb417d07
--- /dev/null
+++ b/src/utils/SkThreadPool.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkThreadPool.h"
+#include "SkRunnable.h"
+#include "SkThreadUtils.h"
+
+SkThreadPool::SkThreadPool(const int count)
+: fDone(false) {
+ // Create count threads, all running SkThreadPool::Loop.
+ for (int i = 0; i < count; i++) {
+ SkThread* thread = SkNEW_ARGS(SkThread, (&SkThreadPool::Loop, this));
+ *fThreads.append() = thread;
+ thread->start();
+ }
+}
+
+SkThreadPool::~SkThreadPool() {
+ fDone = true;
+ fReady.lock();
+ fReady.broadcast();
+ fReady.unlock();
+
+ // Wait for all threads to stop.
+ for (int i = 0; i < fThreads.count(); i++) {
+ fThreads[i]->join();
+ SkDELETE(fThreads[i]);
+ }
+}
+
+/*static*/ void SkThreadPool::Loop(void* arg) {
+ // The SkThreadPool passes itself as arg to each thread as they're created.
+ SkThreadPool* pool = static_cast<SkThreadPool*>(arg);
+
+ while (true) {
+ // We have to be holding the lock to read the queue and to call wait.
+ pool->fReady.lock();
+ while(pool->fQueue.isEmpty()) {
+ // Is it time to die?
+ if (pool->fDone) {
+ pool->fReady.unlock();
+ return;
+ }
+ // wait yields the lock while waiting, but will have it again when awoken.
+ pool->fReady.wait();
+ }
+ // We've got the lock back here, no matter if we ran wait or not.
+
+ // The queue is not empty, so we have something to run. Claim it.
+ LinkedRunnable* r = pool->fQueue.tail();
+
+ pool->fQueue.remove(r);
+
+ // Having claimed our SkRunnable, we now give up the lock while we run it.
+ // Otherwise, we'd only ever do work on one thread at a time, which rather
+ // defeats the point of this code.
+ pool->fReady.unlock();
+
+ // OK, now really do the work.
+ r->fRunnable->run();
+ SkDELETE(r);
+ }
+
+ SkASSERT(false); // Unreachable. The only exit happens when pool->fDone.
+}
+
+void SkThreadPool::add(SkRunnable* r) {
+ if (NULL == r) {
+ return;
+ }
+
+ // If we don't have any threads, obligingly just run the thing now.
+ if (fThreads.isEmpty()) {
+ return r->run();
+ }
+
+ // We have some threads. Queue it up!
+ fReady.lock();
+ LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable);
+ linkedRunnable->fRunnable = r;
+ fQueue.addToHead(linkedRunnable);
+ fReady.signal();
+ fReady.unlock();
+}