| 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 |