Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / test / base-unittests / platform / condition-variable-unittest.cc
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