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.
5 #include "src/base/platform/condition-variable.h"
7 #include "src/base/platform/platform.h"
8 #include "src/base/platform/time.h"
9 #include "testing/gtest/include/gtest/gtest.h"
14 TEST(ConditionVariable, WaitForAfterNofityOnSameThread) {
15 for (int n = 0; n < 10; ++n) {
19 LockGuard<Mutex> lock_guard(&mutex);
22 EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
25 EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
32 class ThreadWithMutexAndConditionVariable V8_FINAL : public Thread {
34 ThreadWithMutexAndConditionVariable()
35 : Thread(Options("ThreadWithMutexAndConditionVariable")),
38 virtual ~ThreadWithMutexAndConditionVariable() {}
40 virtual void Run() V8_OVERRIDE {
41 LockGuard<Mutex> lock_guard(&mutex_);
53 ConditionVariable cv_;
60 TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) {
61 static const int kThreadCount = 128;
62 ThreadWithMutexAndConditionVariable threads[kThreadCount];
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_);
69 // Wait for nth thread to start.
70 while (!threads[n].running_) {
71 threads[n].cv_.Wait(&threads[n].mutex_);
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_);
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();
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_);
96 EXPECT_FALSE(threads[n].running_);
97 EXPECT_TRUE(threads[n].finished_);
100 for (int n = 0; n < kThreadCount; ++n) {
102 LockGuard<Mutex> lock_guard(&threads[n].mutex_);
103 EXPECT_FALSE(threads[n].running_);
104 EXPECT_TRUE(threads[n].finished_);
111 class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread {
113 ThreadWithSharedMutexAndConditionVariable()
114 : Thread(Options("ThreadWithSharedMutexAndConditionVariable")),
119 virtual ~ThreadWithSharedMutexAndConditionVariable() {}
121 virtual void Run() V8_OVERRIDE {
122 LockGuard<Mutex> lock_guard(mutex_);
134 ConditionVariable* cv_;
141 TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) {
142 static const int kThreadCount = 128;
143 ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
144 ConditionVariable cv;
147 for (int n = 0; n < kThreadCount; ++n) {
148 threads[n].mutex_ = &mutex;
149 threads[n].cv_ = &cv;
152 // Start all threads.
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_);
162 // Wait for all threads to start.
164 LockGuard<Mutex> lock_guard(&mutex);
165 for (int n = kThreadCount - 1; n >= 0; --n) {
166 while (!threads[n].running_) {
172 // Make sure that all threads are running.
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_);
181 // Tell all threads to quit.
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;
193 // Wait for all threads to quit.
195 LockGuard<Mutex> lock_guard(&mutex);
196 for (int n = 0; n < kThreadCount; ++n) {
197 while (!threads[n].finished_) {
203 // Make sure all threads are finished.
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_);
213 for (int n = 0; n < kThreadCount; ++n) {
221 class LoopIncrementThread V8_FINAL : public Thread {
223 LoopIncrementThread(int rem, int* counter, int limit, int thread_count,
224 ConditionVariable* cv, Mutex* mutex)
225 : Thread(Options("LoopIncrementThread")),
229 thread_count_(thread_count),
232 EXPECT_LT(rem, thread_count);
233 EXPECT_EQ(0, limit % thread_count);
236 virtual void Run() V8_OVERRIDE {
239 LockGuard<Mutex> lock_guard(mutex_);
240 int count = *counter_;
241 while (count % thread_count_ != rem_ && count < limit_) {
245 if (count >= limit_) break;
246 EXPECT_EQ(*counter_, count);
247 if (last_count != -1) {
248 EXPECT_EQ(last_count + (thread_count_ - 1), count);
261 const int thread_count_;
262 ConditionVariable* cv_;
269 TEST(ConditionVariable, LoopIncrement) {
270 static const int kMaxThreadCount = 16;
272 ConditionVariable cv;
273 for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
274 int limit = thread_count * 10;
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);
284 // Start all threads.
285 for (int n = thread_count - 1; n >= 0; --n) {
289 // Join and cleanup all threads.
290 for (int n = 0; n < thread_count; ++n) {
296 EXPECT_EQ(limit, counter);