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(Options("ThreadWithMutexAndConditionVariable")), | |
36 running_(false), | |
37 finished_(false) {} | |
38 virtual ~ThreadWithMutexAndConditionVariable() {} | |
39 | |
40 virtual void Run() V8_OVERRIDE { | |
41 LockGuard<Mutex> lock_guard(&mutex_); | |
42 running_ = true; | |
43 cv_.NotifyOne(); | |
44 while (running_) { | |
45 cv_.Wait(&mutex_); | |
46 } | |
47 finished_ = true; | |
48 cv_.NotifyAll(); | |
49 } | |
50 | |
51 bool running_; | |
52 bool finished_; | |
53 ConditionVariable cv_; | |
54 Mutex mutex_; | |
55 }; | |
56 | |
57 } | |
58 | |
59 | |
60 TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { | |
61 static const int kThreadCount = 128; | |
62 ThreadWithMutexAndConditionVariable threads[kThreadCount]; | |
63 | |
64 for (int n = 0; n < kThreadCount; ++n) { | |
65 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
66 EXPECT_FALSE(threads[n].running_); | |
67 EXPECT_FALSE(threads[n].finished_); | |
68 threads[n].Start(); | |
69 // Wait for nth thread to start. | |
70 while (!threads[n].running_) { | |
71 threads[n].cv_.Wait(&threads[n].mutex_); | |
72 } | |
73 } | |
74 | |
75 for (int n = kThreadCount - 1; n >= 0; --n) { | |
76 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
77 EXPECT_TRUE(threads[n].running_); | |
78 EXPECT_FALSE(threads[n].finished_); | |
79 } | |
80 | |
81 for (int n = 0; n < kThreadCount; ++n) { | |
82 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
83 EXPECT_TRUE(threads[n].running_); | |
84 EXPECT_FALSE(threads[n].finished_); | |
85 // Tell the nth thread to quit. | |
86 threads[n].running_ = false; | |
87 threads[n].cv_.NotifyOne(); | |
88 } | |
89 | |
90 for (int n = kThreadCount - 1; n >= 0; --n) { | |
91 // Wait for nth thread to quit. | |
92 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
93 while (!threads[n].finished_) { | |
94 threads[n].cv_.Wait(&threads[n].mutex_); | |
95 } | |
96 EXPECT_FALSE(threads[n].running_); | |
97 EXPECT_TRUE(threads[n].finished_); | |
98 } | |
99 | |
100 for (int n = 0; n < kThreadCount; ++n) { | |
101 threads[n].Join(); | |
102 LockGuard<Mutex> lock_guard(&threads[n].mutex_); | |
103 EXPECT_FALSE(threads[n].running_); | |
104 EXPECT_TRUE(threads[n].finished_); | |
105 } | |
106 } | |
107 | |
108 | |
109 namespace { | |
110 | |
111 class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread { | |
112 public: | |
113 ThreadWithSharedMutexAndConditionVariable() | |
114 : Thread(Options("ThreadWithSharedMutexAndConditionVariable")), | |
115 running_(false), | |
116 finished_(false), | |
117 cv_(NULL), | |
118 mutex_(NULL) {} | |
119 virtual ~ThreadWithSharedMutexAndConditionVariable() {} | |
120 | |
121 virtual void Run() V8_OVERRIDE { | |
122 LockGuard<Mutex> lock_guard(mutex_); | |
123 running_ = true; | |
124 cv_->NotifyAll(); | |
125 while (running_) { | |
126 cv_->Wait(mutex_); | |
127 } | |
128 finished_ = true; | |
129 cv_->NotifyAll(); | |
130 } | |
131 | |
132 bool running_; | |
133 bool finished_; | |
134 ConditionVariable* cv_; | |
135 Mutex* mutex_; | |
136 }; | |
137 | |
138 } | |
139 | |
140 | |
141 TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { | |
142 static const int kThreadCount = 128; | |
143 ThreadWithSharedMutexAndConditionVariable threads[kThreadCount]; | |
144 ConditionVariable cv; | |
145 Mutex mutex; | |
146 | |
147 for (int n = 0; n < kThreadCount; ++n) { | |
148 threads[n].mutex_ = &mutex; | |
149 threads[n].cv_ = &cv; | |
150 } | |
151 | |
152 // Start all threads. | |
153 { | |
154 LockGuard<Mutex> lock_guard(&mutex); | |
155 for (int n = 0; n < kThreadCount; ++n) { | |
156 EXPECT_FALSE(threads[n].running_); | |
157 EXPECT_FALSE(threads[n].finished_); | |
158 threads[n].Start(); | |
159 } | |
160 } | |
161 | |
162 // Wait for all threads to start. | |
163 { | |
164 LockGuard<Mutex> lock_guard(&mutex); | |
165 for (int n = kThreadCount - 1; n >= 0; --n) { | |
166 while (!threads[n].running_) { | |
167 cv.Wait(&mutex); | |
168 } | |
169 } | |
170 } | |
171 | |
172 // Make sure that all threads are running. | |
173 { | |
174 LockGuard<Mutex> lock_guard(&mutex); | |
175 for (int n = 0; n < kThreadCount; ++n) { | |
176 EXPECT_TRUE(threads[n].running_); | |
177 EXPECT_FALSE(threads[n].finished_); | |
178 } | |
179 } | |
180 | |
181 // Tell all threads to quit. | |
182 { | |
183 LockGuard<Mutex> lock_guard(&mutex); | |
184 for (int n = kThreadCount - 1; n >= 0; --n) { | |
185 EXPECT_TRUE(threads[n].running_); | |
186 EXPECT_FALSE(threads[n].finished_); | |
187 // Tell the nth thread to quit. | |
188 threads[n].running_ = false; | |
189 } | |
190 cv.NotifyAll(); | |
191 } | |
192 | |
193 // Wait for all threads to quit. | |
194 { | |
195 LockGuard<Mutex> lock_guard(&mutex); | |
196 for (int n = 0; n < kThreadCount; ++n) { | |
197 while (!threads[n].finished_) { | |
198 cv.Wait(&mutex); | |
199 } | |
200 } | |
201 } | |
202 | |
203 // Make sure all threads are finished. | |
204 { | |
205 LockGuard<Mutex> lock_guard(&mutex); | |
206 for (int n = kThreadCount - 1; n >= 0; --n) { | |
207 EXPECT_FALSE(threads[n].running_); | |
208 EXPECT_TRUE(threads[n].finished_); | |
209 } | |
210 } | |
211 | |
212 // Join all threads. | |
213 for (int n = 0; n < kThreadCount; ++n) { | |
214 threads[n].Join(); | |
215 } | |
216 } | |
217 | |
218 | |
219 namespace { | |
220 | |
221 class LoopIncrementThread V8_FINAL : public Thread { | |
222 public: | |
223 LoopIncrementThread(int rem, int* counter, int limit, int thread_count, | |
224 ConditionVariable* cv, Mutex* mutex) | |
225 : Thread(Options("LoopIncrementThread")), | |
226 rem_(rem), | |
227 counter_(counter), | |
228 limit_(limit), | |
229 thread_count_(thread_count), | |
230 cv_(cv), | |
231 mutex_(mutex) { | |
232 EXPECT_LT(rem, thread_count); | |
233 EXPECT_EQ(0, limit % thread_count); | |
234 } | |
235 | |
236 virtual void Run() V8_OVERRIDE { | |
237 int last_count = -1; | |
238 while (true) { | |
239 LockGuard<Mutex> lock_guard(mutex_); | |
240 int count = *counter_; | |
241 while (count % thread_count_ != rem_ && count < limit_) { | |
242 cv_->Wait(mutex_); | |
243 count = *counter_; | |
244 } | |
245 if (count >= limit_) break; | |
246 EXPECT_EQ(*counter_, count); | |
247 if (last_count != -1) { | |
248 EXPECT_EQ(last_count + (thread_count_ - 1), count); | |
249 } | |
250 count++; | |
251 *counter_ = count; | |
252 last_count = count; | |
253 cv_->NotifyAll(); | |
254 } | |
255 } | |
256 | |
257 private: | |
258 const int rem_; | |
259 int* counter_; | |
260 const int limit_; | |
261 const int thread_count_; | |
262 ConditionVariable* cv_; | |
263 Mutex* mutex_; | |
264 }; | |
265 | |
266 } | |
267 | |
268 | |
269 TEST(ConditionVariable, LoopIncrement) { | |
270 static const int kMaxThreadCount = 16; | |
271 Mutex mutex; | |
272 ConditionVariable cv; | |
273 for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) { | |
274 int limit = thread_count * 10; | |
275 int counter = 0; | |
276 | |
277 // Setup the threads. | |
278 Thread** threads = new Thread*[thread_count]; | |
279 for (int n = 0; n < thread_count; ++n) { | |
280 threads[n] = new LoopIncrementThread( | |
281 n, &counter, limit, thread_count, &cv, &mutex); | |
282 } | |
283 | |
284 // Start all threads. | |
285 for (int n = thread_count - 1; n >= 0; --n) { | |
286 threads[n]->Start(); | |
287 } | |
288 | |
289 // Join and cleanup all threads. | |
290 for (int n = 0; n < thread_count; ++n) { | |
291 threads[n]->Join(); | |
292 delete threads[n]; | |
293 } | |
294 delete[] threads; | |
295 | |
296 EXPECT_EQ(limit, counter); | |
297 } | |
298 } | |
299 | |
300 } // namespace base | |
301 } // namespace v8 | |
OLD | NEW |