Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Unified Diff: runtime/vm/thread_pool_test.cc

Issue 9581039: Implement ThreadPool. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/thread_pool_test.cc
===================================================================
--- runtime/vm/thread_pool_test.cc (revision 0)
+++ runtime/vm/thread_pool_test.cc (revision 0)
@@ -0,0 +1,220 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/os.h"
+#include "vm/thread.h"
+#include "vm/thread_pool.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+DECLARE_FLAG(int, worker_timeout_millis);
+
+
+class ThreadPoolTestPeer {
+ public:
+ // When the pool has an exit monitor, workers notify a monitor just
+ // before they exit. This is only used in tests to make sure that
+ // Shutdown works.
+ static void SetExitMonitor(Monitor* exit_monitor, int* exit_count) {
+ ThreadPool::exit_monitor_ = exit_monitor;
+ ThreadPool::exit_count_ = exit_count;
+ }
+};
+
+
+UNIT_TEST_CASE(ThreadPool_Create) {
+ ThreadPool thread_pool;
+}
+
+
+class TestTask : public ThreadPool::Task {
+ public:
+ TestTask(Monitor* sync, bool* done)
+ : sync_(sync), done_(done) {
+ }
+
+ void Run() {
+ MonitorLocker ml(sync_);
+ *done_ = true;
+ ml.Notify();
+ }
+
+ private:
+ Monitor* sync_;
+ bool* done_;
+};
+
+
+UNIT_TEST_CASE(ThreadPool_RunOne) {
+ ThreadPool thread_pool;
+ Monitor sync;
+ bool done = false;
+ thread_pool.Run(new TestTask(&sync, &done));
+ {
+ MonitorLocker ml(&sync);
+ while (!done) {
+ ml.Wait();
+ }
+ }
+ EXPECT(done);
+
+ // Do a sanity test on the worker stats.
+ EXPECT_EQ(1, thread_pool.workers_started());
+ EXPECT_EQ(0, thread_pool.workers_stopped());
+ EXPECT_EQ(1, thread_pool.workers_idle());
+ EXPECT_EQ(0, thread_pool.workers_running());
+}
+
+
+UNIT_TEST_CASE(ThreadPool_RunMany) {
+ const int kTaskCount = 100;
+ ThreadPool thread_pool;
+ Monitor sync[kTaskCount];
+ bool done[kTaskCount];
+
+ for (int i = 0; i < kTaskCount; i++) {
+ done[i] = false;
+ thread_pool.Run(new TestTask(&sync[i], &done[i]));
+ }
+ for (int i = 0; i < kTaskCount; i++) {
+ MonitorLocker ml(&sync[i]);
+ while (!done[i]) {
+ ml.Wait();
+ }
+ EXPECT(done[i]);
+ }
+}
+
+
+class SleepTask : public ThreadPool::Task {
+ public:
+ explicit SleepTask(int millis)
+ : millis_(millis) {
+ }
+
+ void Run() {
+ OS::Sleep(millis_);
+ }
+
+ private:
+ int millis_;
+};
+
+
+UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
+ Monitor exit_sync;
+ int exit_count = 0;
+ MonitorLocker ml(&exit_sync);
+
+ // Set up the ThreadPool so that workers notify before they exit.
+ ThreadPool* thread_pool = new ThreadPool();
+ ThreadPoolTestPeer::SetExitMonitor(&exit_sync, &exit_count);
+
+ // Run a single task.
+ thread_pool->Run(new SleepTask(2));
+
+ // Kill the thread pool.
+ delete thread_pool;
+ thread_pool = NULL;
+
+ // Wait for the workers to terminate.
+ while (exit_count == 0) {
+ ml.Wait();
+ }
+ EXPECT_EQ(1, exit_count);
+}
+
+
+UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
+ // Adjust the worker timeout so that we timeout quickly.
+ int saved_timeout = FLAG_worker_timeout_millis;
+ FLAG_worker_timeout_millis = 1;
+
+ ThreadPool thread_pool;
+ EXPECT_EQ(0, thread_pool.workers_started());
+ EXPECT_EQ(0, thread_pool.workers_stopped());
+
+ // Run a worker.
+ Monitor sync;
+ bool done = false;
+ thread_pool.Run(new TestTask(&sync, &done));
+ EXPECT_EQ(1, thread_pool.workers_started());
+ EXPECT_EQ(0, thread_pool.workers_stopped());
+ {
+ MonitorLocker ml(&sync);
+ while (!done) {
+ ml.Wait();
+ }
+ }
+ EXPECT(done);
+
+ // Wait up to 5 seconds to see if a worker times out.
+ const int kMaxWait = 5000;
+ int waited = 0;
+ while (thread_pool.workers_stopped() == 0 && waited < kMaxWait) {
+ OS::Sleep(1);
+ waited += 1;
+ }
+ EXPECT_EQ(1, thread_pool.workers_stopped());
+ FLAG_worker_timeout_millis = saved_timeout;
+}
+
+
+class SpawnTask : public ThreadPool::Task {
+ public:
+ SpawnTask(ThreadPool* pool, Monitor* sync, int todo, int total, int* done)
+ : pool_(pool), sync_(sync), todo_(todo), total_(total), done_(done) {
+ }
+
+ void Run() {
+ todo_--; // Subtract one for current task.
+ int child_todo = todo_ / 2;
+
+ // Spawn 0-2 children.
+ if (todo_ > 0) {
+ pool_->Run(
+ new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_));
+ }
+ if (todo_ > 1) {
+ pool_->Run(
+ new SpawnTask(pool_, sync_, child_todo, total_, done_));
+ }
+
+ {
+ MonitorLocker ml(sync_);
+ (*done_)++;
+ if (*done_ >= total_) {
+ ml.Notify();
+ }
+ }
+ }
+
+ private:
+ ThreadPool* pool_;
+ Monitor* sync_;
+ int todo_;
+ int total_;
+ int* done_;
+};
+
+
+UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
+ ThreadPool thread_pool;
+ Monitor sync;
+ const int kTotalTasks = 500;
+ int done = 0;
+ thread_pool.Run(
+ new SpawnTask(&thread_pool, &sync, kTotalTasks, kTotalTasks, &done));
+ {
+ MonitorLocker ml(&sync);
+ while (done < kTotalTasks) {
+ ml.Wait();
+ }
+ }
+ EXPECT_EQ(kTotalTasks, done);
+}
+
+
+} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698