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

Side by Side Diff: runtime/vm/thread_pool_test.cc

Issue 1177153005: Enables clean VM shutdown. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Kill isolates from the service isolate Created 5 years, 5 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/os.h" 5 #include "vm/os.h"
6 #include "vm/lockers.h" 6 #include "vm/lockers.h"
7 #include "vm/thread_pool.h" 7 #include "vm/thread_pool.h"
8 #include "vm/unit_test.h" 8 #include "vm/unit_test.h"
9 9
10 namespace dart { 10 namespace dart {
11 11
12 DECLARE_FLAG(int, worker_timeout_millis); 12 DECLARE_FLAG(int, worker_timeout_millis);
13 13
14
15 class ThreadPoolTestPeer {
16 public:
17 // When the pool has an exit monitor, workers notify a monitor just
18 // before they exit. This is only used in tests to make sure that
19 // Shutdown works.
20 static void SetExitMonitor(Monitor* exit_monitor, int* exit_count) {
21 ThreadPool::exit_monitor_ = exit_monitor;
22 ThreadPool::exit_count_ = exit_count;
23 }
24 };
25
26
27 UNIT_TEST_CASE(ThreadPool_Create) {
28 ThreadPool thread_pool;
29 }
30
31
32 class TestTask : public ThreadPool::Task { 14 class TestTask : public ThreadPool::Task {
33 public: 15 public:
34 TestTask(Monitor* sync, bool* done) 16 TestTask(Monitor* sync, bool* done)
35 : sync_(sync), done_(done) { 17 : sync_(sync), done_(done) {
36 } 18 }
37 19
38 virtual void Run() { 20 virtual void Run() {
39 MonitorLocker ml(sync_); 21 MonitorLocker ml(sync_);
40 *done_ = true; 22 *done_ = true;
41 ml.Notify(); 23 ml.Notify();
42 } 24 }
43 25
44 private: 26 private:
45 Monitor* sync_; 27 Monitor* sync_;
46 bool* done_; 28 bool* done_;
47 }; 29 };
48 30
49 31
50 UNIT_TEST_CASE(ThreadPool_RunOne) { 32 UNIT_TEST_CASE(ThreadPool_RunOne) {
51 ThreadPool thread_pool; 33 ThreadPool::set_shutdown_timeout_fatal(false);
52 Monitor sync; 34 Monitor sync;
53 bool done = false; 35 bool done = false;
54 thread_pool.Run(new TestTask(&sync, &done)); 36 ThreadPool::Run(new TestTask(&sync, &done));
55 { 37 {
56 MonitorLocker ml(&sync); 38 MonitorLocker ml(&sync);
57 while (!done) { 39 while (!done) {
58 ml.Wait(); 40 ml.Wait();
59 } 41 }
60 } 42 }
61 EXPECT(done); 43 EXPECT(done);
62 44
63 // Do a sanity test on the worker stats. 45 // Do a sanity test on the worker stats.
64 EXPECT_EQ(1U, thread_pool.workers_started()); 46 EXPECT_LE(1U, ThreadPool::workers_started());
65 EXPECT_EQ(0U, thread_pool.workers_stopped()); 47 EXPECT_EQ(0U, ThreadPool::workers_stopped());
48 EXPECT(ThreadPool::Shutdown());
66 } 49 }
67 50
68 51
69 UNIT_TEST_CASE(ThreadPool_RunMany) { 52 UNIT_TEST_CASE(ThreadPool_RunMany) {
53 ThreadPool::set_shutdown_timeout_fatal(false);
70 const int kTaskCount = 100; 54 const int kTaskCount = 100;
71 ThreadPool thread_pool;
72 Monitor sync[kTaskCount]; 55 Monitor sync[kTaskCount];
73 bool done[kTaskCount]; 56 bool done[kTaskCount];
74 57
75 for (int i = 0; i < kTaskCount; i++) { 58 for (int i = 0; i < kTaskCount; i++) {
76 done[i] = false; 59 done[i] = false;
77 thread_pool.Run(new TestTask(&sync[i], &done[i])); 60 ThreadPool::Run(new TestTask(&sync[i], &done[i]));
78 } 61 }
79 for (int i = 0; i < kTaskCount; i++) { 62 for (int i = 0; i < kTaskCount; i++) {
80 MonitorLocker ml(&sync[i]); 63 MonitorLocker ml(&sync[i]);
81 while (!done[i]) { 64 while (!done[i]) {
82 ml.Wait(); 65 ml.Wait();
83 } 66 }
84 EXPECT(done[i]); 67 EXPECT(done[i]);
85 } 68 }
69 EXPECT(ThreadPool::Shutdown());
86 } 70 }
87 71
88 72
89 class SleepTask : public ThreadPool::Task {
90 public:
91 explicit SleepTask(int millis)
92 : millis_(millis) {
93 }
94
95 virtual void Run() {
96 OS::Sleep(millis_);
97 }
98
99 private:
100 int millis_;
101 };
102
103
104 UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
105 Monitor exit_sync;
106 int exit_count = 0;
107 MonitorLocker ml(&exit_sync);
108
109 // Set up the ThreadPool so that workers notify before they exit.
110 ThreadPool* thread_pool = new ThreadPool();
111 ThreadPoolTestPeer::SetExitMonitor(&exit_sync, &exit_count);
112
113 // Run a single task.
114 thread_pool->Run(new SleepTask(2));
115
116 // Kill the thread pool.
117 delete thread_pool;
118 thread_pool = NULL;
119
120 // Wait for the workers to terminate.
121 while (exit_count == 0) {
122 ml.Wait();
123 }
124 EXPECT_EQ(1, exit_count);
125 }
126
127
128 UNIT_TEST_CASE(ThreadPool_WorkerTimeout) { 73 UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
129 // Adjust the worker timeout so that we timeout quickly. 74 // Adjust the worker timeout so that we timeout quickly.
130 int saved_timeout = FLAG_worker_timeout_millis; 75 int saved_timeout = FLAG_worker_timeout_millis;
131 FLAG_worker_timeout_millis = 1; 76 FLAG_worker_timeout_millis = 1;
132 77
133 ThreadPool thread_pool; 78 ThreadPool::set_shutdown_timeout_fatal(false);
134 EXPECT_EQ(0U, thread_pool.workers_started()); 79 EXPECT_LE(0U, ThreadPool::workers_started());
135 EXPECT_EQ(0U, thread_pool.workers_stopped()); 80 EXPECT_EQ(0U, ThreadPool::workers_stopped());
136 81
137 // Run a worker. 82 // Run a worker.
138 Monitor sync; 83 Monitor sync;
139 bool done = false; 84 bool done = false;
140 thread_pool.Run(new TestTask(&sync, &done)); 85 ThreadPool::Run(new TestTask(&sync, &done));
141 EXPECT_EQ(1U, thread_pool.workers_started()); 86 EXPECT_LE(1U, ThreadPool::workers_started());
142 EXPECT_EQ(0U, thread_pool.workers_stopped()); 87 EXPECT_EQ(0U, ThreadPool::workers_stopped());
143 { 88 {
144 MonitorLocker ml(&sync); 89 MonitorLocker ml(&sync);
145 while (!done) { 90 while (!done) {
146 ml.Wait(); 91 ml.Wait();
147 } 92 }
148 } 93 }
149 EXPECT(done); 94 EXPECT(done);
150 95
151 // Wait up to 5 seconds to see if a worker times out. 96 // Wait up to 5 seconds to see if a worker times out.
152 const int kMaxWait = 5000; 97 const int kMaxWait = 5000;
153 int waited = 0; 98 int waited = 0;
154 while (thread_pool.workers_stopped() == 0 && waited < kMaxWait) { 99 while (ThreadPool::workers_stopped() == 0 && waited < kMaxWait) {
155 OS::Sleep(1); 100 OS::Sleep(1);
156 waited += 1; 101 waited += 1;
157 } 102 }
158 EXPECT_EQ(1U, thread_pool.workers_stopped()); 103 EXPECT_LE(1U, ThreadPool::workers_stopped());
159 FLAG_worker_timeout_millis = saved_timeout; 104 FLAG_worker_timeout_millis = saved_timeout;
105
106 EXPECT(ThreadPool::Shutdown());
160 } 107 }
161 108
162 109
163 class SpawnTask : public ThreadPool::Task { 110 class SpawnTask : public ThreadPool::Task {
164 public: 111 public:
165 SpawnTask(ThreadPool* pool, Monitor* sync, int todo, int total, int* done) 112 SpawnTask(Monitor* sync, int todo, int total, int* done)
166 : pool_(pool), sync_(sync), todo_(todo), total_(total), done_(done) { 113 : sync_(sync), todo_(todo), total_(total), done_(done) {
167 } 114 }
168 115
169 virtual void Run() { 116 virtual void Run() {
170 todo_--; // Subtract one for current task. 117 todo_--; // Subtract one for current task.
171 int child_todo = todo_ / 2; 118 int child_todo = todo_ / 2;
172 119
173 // Spawn 0-2 children. 120 // Spawn 0-2 children.
174 if (todo_ > 0) { 121 if (todo_ > 0) {
175 pool_->Run( 122 ThreadPool::Run(
176 new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_)); 123 new SpawnTask(sync_, todo_ - child_todo, total_, done_));
177 } 124 }
178 if (todo_ > 1) { 125 if (todo_ > 1) {
179 pool_->Run( 126 ThreadPool::Run(
180 new SpawnTask(pool_, sync_, child_todo, total_, done_)); 127 new SpawnTask(sync_, child_todo, total_, done_));
181 } 128 }
182 129
183 { 130 {
184 MonitorLocker ml(sync_); 131 MonitorLocker ml(sync_);
185 (*done_)++; 132 (*done_)++;
186 if (*done_ >= total_) { 133 if (*done_ >= total_) {
187 ml.Notify(); 134 ml.Notify();
188 } 135 }
189 } 136 }
190 } 137 }
191 138
192 private: 139 private:
193 ThreadPool* pool_;
194 Monitor* sync_; 140 Monitor* sync_;
195 int todo_; 141 int todo_;
196 int total_; 142 int total_;
197 int* done_; 143 int* done_;
198 }; 144 };
199 145
200 146
201 UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) { 147 UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
202 ThreadPool thread_pool; 148 ThreadPool::set_shutdown_timeout_fatal(false);
203 Monitor sync; 149 Monitor sync;
204 const int kTotalTasks = 500; 150 const int kTotalTasks = 500;
205 int done = 0; 151 int done = 0;
206 thread_pool.Run( 152 ThreadPool::Run(
207 new SpawnTask(&thread_pool, &sync, kTotalTasks, kTotalTasks, &done)); 153 new SpawnTask(&sync, kTotalTasks, kTotalTasks, &done));
208 { 154 {
209 MonitorLocker ml(&sync); 155 MonitorLocker ml(&sync);
210 while (done < kTotalTasks) { 156 while (done < kTotalTasks) {
211 ml.Wait(); 157 ml.Wait();
212 } 158 }
213 } 159 }
214 EXPECT_EQ(kTotalTasks, done); 160 EXPECT_EQ(kTotalTasks, done);
161 EXPECT(ThreadPool::Shutdown());
215 } 162 }
216 163
217 164
165 class SleepTask : public ThreadPool::Task {
166 public:
167 SleepTask(Monitor* sync, int millis)
168 : sync_(sync), millis_(millis) {
169 }
170
171 virtual void Run() {
172 {
173 MonitorLocker ml(sync_);
174 ml.Notify();
175 }
176 OS::Sleep(millis_);
177 }
178
179 private:
180 Monitor* sync_;
181 int millis_;
182 };
183
184
185 UNIT_TEST_CASE(ThreadPool_ShutdownTimeout) {
186 ThreadPool::set_shutdown_timeout_fatal(false);
187 Monitor sync;
188 ThreadPool::Run(new SleepTask(&sync, 15000));
189 {
190 MonitorLocker ml(&sync);
191 ml.Wait();
192 }
193 EXPECT(!ThreadPool::Shutdown());
194 }
195
196
218 } // namespace dart 197 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698