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