V8 Project
condition-variable-unittest.cc
Go to the documentation of this file.
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 
6 
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 FINAL : public Thread {
33  public:
35  : Thread(Options("ThreadWithMutexAndConditionVariable")),
36  running_(false),
37  finished_(false) {}
39 
40  virtual void Run() 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 } // namespace
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 FINAL : public Thread {
112  public:
114  : Thread(Options("ThreadWithSharedMutexAndConditionVariable")),
115  running_(false),
116  finished_(false),
117  cv_(NULL),
118  mutex_(NULL) {}
120 
121  virtual void Run() 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 } // namespace
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 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() 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 } // namespace
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(n, &counter, limit, thread_count,
281  &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
LoopIncrementThread(int rem, int *counter, int limit, int thread_count, ConditionVariable *cv, Mutex *mutex)
#define OVERRIDE
#define FINAL
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
TEST(CPUTest, FeatureImplications)
Definition: cpu-unittest.cc:11
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20