Index: runtime/vm/thread_pool_test.cc |
diff --git a/runtime/vm/thread_pool_test.cc b/runtime/vm/thread_pool_test.cc |
index 35a61273736c8e80c45f957263f596c289421dcd..af9f618e7edb541e6849d0ae39199bc0888a5db0 100644 |
--- a/runtime/vm/thread_pool_test.cc |
+++ b/runtime/vm/thread_pool_test.cc |
@@ -12,18 +12,6 @@ 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; |
} |
@@ -88,40 +76,74 @@ UNIT_TEST_CASE(ThreadPool_RunMany) { |
class SleepTask : public ThreadPool::Task { |
public: |
- explicit SleepTask(int millis) |
- : millis_(millis) { |
+ explicit SleepTask( |
+ Monitor* sync, int* started_count, int* slept_count, int millis) |
+ : sync_(sync), |
+ started_count_(started_count), |
+ slept_count_(slept_count), |
+ millis_(millis) { |
} |
virtual void Run() { |
+ { |
+ MonitorLocker ml(sync_); |
+ *started_count_ = *started_count_ + 1; |
+ ml.Notify(); |
+ } |
+ // Sleep so we can be sure the ThreadPool destructor blocks until we're |
+ // done. |
OS::Sleep(millis_); |
+ { |
+ MonitorLocker ml(sync_); |
+ *slept_count_ = *slept_count_ + 1; |
+ // No notification here. The main thread is blocked in ThreadPool |
+ // shutdown waiting for this thread to finish. |
+ } |
} |
private: |
+ Monitor* sync_; |
+ int* started_count_; |
+ int* slept_count_; |
int millis_; |
}; |
UNIT_TEST_CASE(ThreadPool_WorkerShutdown) { |
- Monitor exit_sync; |
- int exit_count = 0; |
- MonitorLocker ml(&exit_sync); |
+ const int kTaskCount = 10; |
+ Monitor sync; |
+ int slept_count = 0; |
+ int started_count = 0; |
// 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)); |
+ for (int i = 0; i < kTaskCount; i++) { |
+ thread_pool->Run(new SleepTask(&sync, &started_count, &slept_count, 2)); |
+ } |
+ |
+ { |
+ // Wait for everybody to start. |
+ MonitorLocker ml(&sync); |
+ while (started_count < kTaskCount) { |
+ ml.Wait(); |
+ } |
+ } |
- // Kill the thread pool. |
+ // Kill the thread pool while the workers are sleeping. |
delete thread_pool; |
thread_pool = NULL; |
- // Wait for the workers to terminate. |
- while (exit_count == 0) { |
- ml.Wait(); |
+ int final_count = 0; |
+ { |
+ MonitorLocker ml(&sync); |
+ final_count = slept_count; |
} |
- EXPECT_EQ(1, exit_count); |
+ |
+ // We should have waited for all the workers to finish, so they all should |
+ // have had a chance to increment slept_count. |
+ EXPECT_EQ(kTaskCount, final_count); |
} |
@@ -172,12 +194,11 @@ class SpawnTask : public ThreadPool::Task { |
// Spawn 0-2 children. |
if (todo_ > 0) { |
- pool_->Run( |
- new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_)); |
+ pool_->Run(new SpawnTask( |
+ pool_, sync_, todo_ - child_todo, total_, done_)); |
} |
if (todo_ > 1) { |
- pool_->Run( |
- new SpawnTask(pool_, sync_, child_todo, total_, done_)); |
+ pool_->Run(new SpawnTask(pool_, sync_, child_todo, total_, done_)); |
} |
{ |
@@ -214,5 +235,4 @@ UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) { |
EXPECT_EQ(kTotalTasks, done); |
} |
- |
} // namespace dart |