OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/base/platform/condition-variable.h" | |
6 | |
7 #include "src/base/platform/platform.h" | |
8 #include "src/base/platform/time.h" | |
9 #include "testing/gtest/include/gtest/gtest.h" | |
10 | |
11 namespace v8 { | |
12 namespace base { | |
13 | |
14 TEST(ConditionVariable, WaitForAfterNofityOnSameThread) { | |
15 for (int n = 0; n < 10; ++n) { | |
16 Mutex mutex; | |
17 ConditionVariable cv; | |
18 | |
19 LockGuard<Mutex> lock_guard(&mutex); | |
20 | |
21 cv.NotifyOne(); | |
22 EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n))); | |
23 | |
24 cv.NotifyAll(); | |
25 EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n))); | |
26 } | |
27 } | |
28 | |
29 | |
30 namespace { | |
31 | |
32 class ThreadWithMutexAndConditionVariable V8_FINAL : public Thread { | |
33 public: | |
34 ThreadWithMutexAndConditionVariable() | |
35 : Thread("ThreadWithMutexAndConditionVariable"), | |
36 running_(false), finished_(false) {} | |
37 virtual ~ThreadWithMutexAndConditionVariable() {} | |
38 | |
39 virtual void Run() V8_OVERRIDE { | |
40 LockGuard<Mutex> lock_guard(&mutex_); | |
41 running_ = true; | |
42 cv_.NotifyOne(); | |
43 while (running_) { | |
44 cv_.Wait(&mutex_); | |
45 } | |
46 finished_ = true; | |
47 cv_.NotifyAll(); | |
48 } | |
49 | |
50 bool running_; | |
51 bool finished_; | |
52 ConditionVariable cv_; | |
53 Mutex mutex_; | |
54 }; | |
55 | |
56 } | |
57 | |
58 | |
59 TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { | |
60 static const int kThreadCount = 128; | |
61 ThreadWithMutexAndConditionVariable threads[kThreadCount]; | |
62 | |
63 for (int n = 0; n < kThreadCount; ++n) { | |
64 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
65 EXPECT_FALSE(threads[n].running_); | |
66 EXPECT_FALSE(threads[n].finished_); | |
67 threads[n].Start(); | |
68 // Wait for nth thread to start. | |
69 while (!threads[n].running_) { | |
70 threads[n].cv_.Wait(&threads[n].mutex_); | |
71 } | |
72 } | |
73 | |
74 for (int n = kThreadCount - 1; n >= 0; --n) { | |
75 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
76 EXPECT_TRUE(threads[n].running_); | |
77 EXPECT_FALSE(threads[n].finished_); | |
78 } | |
79 | |
80 for (int n = 0; n < kThreadCount; ++n) { | |
81 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
82 EXPECT_TRUE(threads[n].running_); | |
83 EXPECT_FALSE(threads[n].finished_); | |
84 // Tell the nth thread to quit. | |
85 threads[n].running_ = false; | |
86 threads[n].cv_.NotifyOne(); | |
87 } | |
88 | |
89 for (int n = kThreadCount - 1; n >= 0; --n) { | |
90 // Wait for nth thread to quit. | |
91 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
92 while (!threads[n].finished_) { | |
93 threads[n].cv_.Wait(&threads[n].mutex_); | |
94 } | |
95 EXPECT_FALSE(threads[n].running_); | |
96 EXPECT_TRUE(threads[n].finished_); | |
97 } | |
98 | |
99 for (int n = 0; n < kThreadCount; ++n) { | |
100 threads[n].Join(); | |
101 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
102 EXPECT_FALSE(threads[n].running_); | |
103 EXPECT_TRUE(threads[n].finished_); | |
104 } | |
105 } | |
106 | |
107 | |
108 namespace { | |
109 | |
110 class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread { | |
111 public: | |
112 ThreadWithSharedMutexAndConditionVariable() | |
113 : Thread("ThreadWithSharedMutexAndConditionVariable"), | |
114 running_(false), finished_(false), cv_(NULL), mutex_(NULL) {} | |
115 virtual ~ThreadWithSharedMutexAndConditionVariable() {} | |
116 | |
117 virtual void Run() V8_OVERRIDE { | |
118 LockGuard<Mutex> lock_guard(mutex_); | |
119 running_ = true; | |
120 cv_->NotifyAll(); | |
121 while (running_) { | |
122 cv_->Wait(mutex_); | |
123 } | |
124 finished_ = true; | |
125 cv_->NotifyAll(); | |
126 } | |
127 | |
128 bool running_; | |
129 bool finished_; | |
130 ConditionVariable* cv_; | |
131 Mutex* mutex_; | |
132 }; | |
133 | |
134 } | |
135 | |
136 | |
137 TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { | |
138 static const int kThreadCount = 128; | |
139 ThreadWithSharedMutexAndConditionVariable threads[kThreadCount]; | |
140 ConditionVariable cv; | |
141 Mutex mutex; | |
142 | |
143 for (int n = 0; n < kThreadCount; ++n) { | |
144 threads[n].mutex_ = &mutex; | |
145 threads[n].cv_ = &cv; | |
146 } | |
147 | |
148 // Start all threads. | |
149 { | |
150 LockGuard<Mutex> lock_guard(&mutex); | |
151 for (int n = 0; n < kThreadCount; ++n) { | |
152 EXPECT_FALSE(threads[n].running_); | |
153 EXPECT_FALSE(threads[n].finished_); | |
154 threads[n].Start(); | |
155 } | |
156 } | |
157 | |
158 // Wait for all threads to start. | |
159 { | |
160 LockGuard<Mutex> lock_guard(&mutex); | |
161 for (int n = kThreadCount - 1; n >= 0; --n) { | |
162 while (!threads[n].running_) { | |
163 cv.Wait(&mutex); | |
164 } | |
165 } | |
166 } | |
167 | |
168 // Make sure that all threads are running. | |
169 { | |
170 LockGuard<Mutex> lock_guard(&mutex); | |
171 for (int n = 0; n < kThreadCount; ++n) { | |
172 EXPECT_TRUE(threads[n].running_); | |
173 EXPECT_FALSE(threads[n].finished_); | |
174 } | |
175 } | |
176 | |
177 // Tell all threads to quit. | |
178 { | |
179 LockGuard<Mutex> lock_guard(&mutex); | |
180 for (int n = kThreadCount - 1; n >= 0; --n) { | |
181 EXPECT_TRUE(threads[n].running_); | |
182 EXPECT_FALSE(threads[n].finished_); | |
183 // Tell the nth thread to quit. | |
184 threads[n].running_ = false; | |
185 } | |
186 cv.NotifyAll(); | |
187 } | |
188 | |
189 // Wait for all threads to quit. | |
190 { | |
191 LockGuard<Mutex> lock_guard(&mutex); | |
192 for (int n = 0; n < kThreadCount; ++n) { | |
193 while (!threads[n].finished_) { | |
194 cv.Wait(&mutex); | |
195 } | |
196 } | |
197 } | |
198 | |
199 // Make sure all threads are finished. | |
200 { | |
201 LockGuard<Mutex> lock_guard(&mutex); | |
202 for (int n = kThreadCount - 1; n >= 0; --n) { | |
203 EXPECT_FALSE(threads[n].running_); | |
204 EXPECT_TRUE(threads[n].finished_); | |
205 } | |
206 } | |
207 | |
208 // Join all threads. | |
209 for (int n = 0; n < kThreadCount; ++n) { | |
210 threads[n].Join(); | |
211 } | |
212 } | |
213 | |
214 | |
215 namespace { | |
216 | |
217 class LoopIncrementThread V8_FINAL : public Thread { | |
218 public: | |
219 LoopIncrementThread(int rem, | |
220 int* counter, | |
221 int limit, | |
222 int thread_count, | |
223 ConditionVariable* cv, | |
224 Mutex* mutex) | |
225 : Thread("LoopIncrementThread"), rem_(rem), counter_(counter), | |
226 limit_(limit), thread_count_(thread_count), cv_(cv), mutex_(mutex) { | |
227 EXPECT_LT(rem, thread_count); | |
228 EXPECT_EQ(0, limit % thread_count); | |
229 } | |
230 | |
231 virtual void Run() V8_OVERRIDE { | |
232 int last_count = -1; | |
233 while (true) { | |
234 LockGuard<Mutex> lock_guard(mutex_); | |
235 int count = *counter_; | |
236 while (count % thread_count_ != rem_ && count < limit_) { | |
237 cv_->Wait(mutex_); | |
238 count = *counter_; | |
239 } | |
240 if (count >= limit_) break; | |
241 EXPECT_EQ(*counter_, count); | |
242 if (last_count != -1) { | |
243 EXPECT_EQ(last_count + (thread_count_ - 1), count); | |
244 } | |
245 count++; | |
246 *counter_ = count; | |
247 last_count = count; | |
248 cv_->NotifyAll(); | |
249 } | |
250 } | |
251 | |
252 private: | |
253 const int rem_; | |
254 int* counter_; | |
255 const int limit_; | |
256 const int thread_count_; | |
257 ConditionVariable* cv_; | |
258 Mutex* mutex_; | |
259 }; | |
260 | |
261 } | |
262 | |
263 | |
264 TEST(ConditionVariable, LoopIncrement) { | |
265 static const int kMaxThreadCount = 16; | |
266 Mutex mutex; | |
267 ConditionVariable cv; | |
268 for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) { | |
269 int limit = thread_count * 10; | |
270 int counter = 0; | |
271 | |
272 // Setup the threads. | |
273 Thread** threads = new Thread*[thread_count]; | |
Sven Panne
2014/08/06 09:33:28
Use ScopedVector? Or do we explicitly want to avoi
Benedikt Meurer
2014/08/06 09:35:06
ScopedVector is not in base.
| |
274 for (int n = 0; n < thread_count; ++n) { | |
275 threads[n] = new LoopIncrementThread( | |
276 n, &counter, limit, thread_count, &cv, &mutex); | |
277 } | |
278 | |
279 // Start all threads. | |
280 for (int n = thread_count - 1; n >= 0; --n) { | |
281 threads[n]->Start(); | |
282 } | |
283 | |
284 // Join and cleanup all threads. | |
285 for (int n = 0; n < thread_count; ++n) { | |
286 threads[n]->Join(); | |
287 delete threads[n]; | |
288 } | |
289 delete[] threads; | |
290 | |
291 EXPECT_EQ(limit, counter); | |
292 } | |
293 } | |
294 | |
295 } // namespace base | |
296 } // namespace v8 | |
OLD | NEW |