Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-condition-variable.cc
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "src/v8.h"
29
30 #include "src/platform/condition-variable.h"
31 #include "src/platform/time.h"
32 #include "test/cctest/cctest.h"
33
34 using namespace ::v8::internal;
35
36
37 TEST(WaitForAfterNofityOnSameThread) {
38   for (int n = 0; n < 10; ++n) {
39     Mutex mutex;
40     ConditionVariable cv;
41
42     LockGuard<Mutex> lock_guard(&mutex);
43
44     cv.NotifyOne();
45     CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
46
47     cv.NotifyAll();
48     CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
49   }
50 }
51
52
53 class ThreadWithMutexAndConditionVariable V8_FINAL : public Thread {
54  public:
55   ThreadWithMutexAndConditionVariable()
56       : Thread("ThreadWithMutexAndConditionVariable"),
57         running_(false), finished_(false) {}
58   virtual ~ThreadWithMutexAndConditionVariable() {}
59
60   virtual void Run() V8_OVERRIDE {
61     LockGuard<Mutex> lock_guard(&mutex_);
62     running_ = true;
63     cv_.NotifyOne();
64     while (running_) {
65       cv_.Wait(&mutex_);
66     }
67     finished_ = true;
68     cv_.NotifyAll();
69   }
70
71   bool running_;
72   bool finished_;
73   ConditionVariable cv_;
74   Mutex mutex_;
75 };
76
77
78 TEST(MultipleThreadsWithSeparateConditionVariables) {
79   static const int kThreadCount = 128;
80   ThreadWithMutexAndConditionVariable threads[kThreadCount];
81
82   for (int n = 0; n < kThreadCount; ++n) {
83     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
84     CHECK(!threads[n].running_);
85     CHECK(!threads[n].finished_);
86     threads[n].Start();
87     // Wait for nth thread to start.
88     while (!threads[n].running_) {
89       threads[n].cv_.Wait(&threads[n].mutex_);
90     }
91   }
92
93   for (int n = kThreadCount - 1; n >= 0; --n) {
94     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
95     CHECK(threads[n].running_);
96     CHECK(!threads[n].finished_);
97   }
98
99   for (int n = 0; n < kThreadCount; ++n) {
100     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
101     CHECK(threads[n].running_);
102     CHECK(!threads[n].finished_);
103     // Tell the nth thread to quit.
104     threads[n].running_ = false;
105     threads[n].cv_.NotifyOne();
106   }
107
108   for (int n = kThreadCount - 1; n >= 0; --n) {
109     // Wait for nth thread to quit.
110     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
111     while (!threads[n].finished_) {
112       threads[n].cv_.Wait(&threads[n].mutex_);
113     }
114     CHECK(!threads[n].running_);
115     CHECK(threads[n].finished_);
116   }
117
118   for (int n = 0; n < kThreadCount; ++n) {
119     threads[n].Join();
120     LockGuard<Mutex> lock_guard(&threads[n].mutex_);
121     CHECK(!threads[n].running_);
122     CHECK(threads[n].finished_);
123   }
124 }
125
126
127 class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread {
128  public:
129   ThreadWithSharedMutexAndConditionVariable()
130       : Thread("ThreadWithSharedMutexAndConditionVariable"),
131         running_(false), finished_(false), cv_(NULL), mutex_(NULL) {}
132   virtual ~ThreadWithSharedMutexAndConditionVariable() {}
133
134   virtual void Run() V8_OVERRIDE {
135     LockGuard<Mutex> lock_guard(mutex_);
136     running_ = true;
137     cv_->NotifyAll();
138     while (running_) {
139       cv_->Wait(mutex_);
140     }
141     finished_ = true;
142     cv_->NotifyAll();
143   }
144
145   bool running_;
146   bool finished_;
147   ConditionVariable* cv_;
148   Mutex* mutex_;
149 };
150
151
152 TEST(MultipleThreadsWithSharedSeparateConditionVariables) {
153   static const int kThreadCount = 128;
154   ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
155   ConditionVariable cv;
156   Mutex mutex;
157
158   for (int n = 0; n < kThreadCount; ++n) {
159     threads[n].mutex_ = &mutex;
160     threads[n].cv_ = &cv;
161   }
162
163   // Start all threads.
164   {
165     LockGuard<Mutex> lock_guard(&mutex);
166     for (int n = 0; n < kThreadCount; ++n) {
167       CHECK(!threads[n].running_);
168       CHECK(!threads[n].finished_);
169       threads[n].Start();
170     }
171   }
172
173   // Wait for all threads to start.
174   {
175     LockGuard<Mutex> lock_guard(&mutex);
176     for (int n = kThreadCount - 1; n >= 0; --n) {
177       while (!threads[n].running_) {
178         cv.Wait(&mutex);
179       }
180     }
181   }
182
183   // Make sure that all threads are running.
184   {
185     LockGuard<Mutex> lock_guard(&mutex);
186     for (int n = 0; n < kThreadCount; ++n) {
187       CHECK(threads[n].running_);
188       CHECK(!threads[n].finished_);
189     }
190   }
191
192   // Tell all threads to quit.
193   {
194     LockGuard<Mutex> lock_guard(&mutex);
195     for (int n = kThreadCount - 1; n >= 0; --n) {
196       CHECK(threads[n].running_);
197       CHECK(!threads[n].finished_);
198       // Tell the nth thread to quit.
199       threads[n].running_ = false;
200     }
201     cv.NotifyAll();
202   }
203
204   // Wait for all threads to quit.
205   {
206     LockGuard<Mutex> lock_guard(&mutex);
207     for (int n = 0; n < kThreadCount; ++n) {
208       while (!threads[n].finished_) {
209         cv.Wait(&mutex);
210       }
211     }
212   }
213
214   // Make sure all threads are finished.
215   {
216     LockGuard<Mutex> lock_guard(&mutex);
217     for (int n = kThreadCount - 1; n >= 0; --n) {
218       CHECK(!threads[n].running_);
219       CHECK(threads[n].finished_);
220     }
221   }
222
223   // Join all threads.
224   for (int n = 0; n < kThreadCount; ++n) {
225     threads[n].Join();
226   }
227 }
228
229
230 class LoopIncrementThread V8_FINAL : public Thread {
231  public:
232   LoopIncrementThread(int rem,
233                       int* counter,
234                       int limit,
235                       int thread_count,
236                       ConditionVariable* cv,
237                       Mutex* mutex)
238       : Thread("LoopIncrementThread"), rem_(rem), counter_(counter),
239         limit_(limit), thread_count_(thread_count), cv_(cv), mutex_(mutex) {
240     CHECK_LT(rem, thread_count);
241     CHECK_EQ(0, limit % thread_count);
242   }
243
244   virtual void Run() V8_OVERRIDE {
245     int last_count = -1;
246     while (true) {
247       LockGuard<Mutex> lock_guard(mutex_);
248       int count = *counter_;
249       while (count % thread_count_ != rem_ && count < limit_) {
250         cv_->Wait(mutex_);
251         count = *counter_;
252       }
253       if (count >= limit_) break;
254       CHECK_EQ(*counter_, count);
255       if (last_count != -1) {
256         CHECK_EQ(last_count + (thread_count_ - 1), count);
257       }
258       count++;
259       *counter_ = count;
260       last_count = count;
261       cv_->NotifyAll();
262     }
263   }
264
265  private:
266   const int rem_;
267   int* counter_;
268   const int limit_;
269   const int thread_count_;
270   ConditionVariable* cv_;
271   Mutex* mutex_;
272 };
273
274
275 TEST(LoopIncrement) {
276   static const int kMaxThreadCount = 16;
277   Mutex mutex;
278   ConditionVariable cv;
279   for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
280     int limit = thread_count * 100;
281     int counter = 0;
282
283     // Setup the threads.
284     Thread** threads = new Thread*[thread_count];
285     for (int n = 0; n < thread_count; ++n) {
286       threads[n] = new LoopIncrementThread(
287           n, &counter, limit, thread_count, &cv, &mutex);
288     }
289
290     // Start all threads.
291     for (int n = thread_count - 1; n >= 0; --n) {
292       threads[n]->Start();
293     }
294
295     // Join and cleanup all threads.
296     for (int n = 0; n < thread_count; ++n) {
297       threads[n]->Join();
298       delete threads[n];
299     }
300     delete[] threads;
301
302     CHECK_EQ(limit, counter);
303   }
304 }