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