summaryrefslogtreecommitdiff
path: root/deps/v8/src/base/platform/condition-variable-unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/base/platform/condition-variable-unittest.cc')
-rw-r--r--deps/v8/src/base/platform/condition-variable-unittest.cc301
1 files changed, 301 insertions, 0 deletions
diff --git a/deps/v8/src/base/platform/condition-variable-unittest.cc b/deps/v8/src/base/platform/condition-variable-unittest.cc
new file mode 100644
index 0000000000..fe0ad2ade8
--- /dev/null
+++ b/deps/v8/src/base/platform/condition-variable-unittest.cc
@@ -0,0 +1,301 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/condition-variable.h"
+
+#include "src/base/platform/platform.h"
+#include "src/base/platform/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+TEST(ConditionVariable, WaitForAfterNofityOnSameThread) {
+ for (int n = 0; n < 10; ++n) {
+ Mutex mutex;
+ ConditionVariable cv;
+
+ LockGuard<Mutex> lock_guard(&mutex);
+
+ cv.NotifyOne();
+ EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
+
+ cv.NotifyAll();
+ EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
+ }
+}
+
+
+namespace {
+
+class ThreadWithMutexAndConditionVariable FINAL : public Thread {
+ public:
+ ThreadWithMutexAndConditionVariable()
+ : Thread(Options("ThreadWithMutexAndConditionVariable")),
+ running_(false),
+ finished_(false) {}
+ virtual ~ThreadWithMutexAndConditionVariable() {}
+
+ virtual void Run() OVERRIDE {
+ LockGuard<Mutex> lock_guard(&mutex_);
+ running_ = true;
+ cv_.NotifyOne();
+ while (running_) {
+ cv_.Wait(&mutex_);
+ }
+ finished_ = true;
+ cv_.NotifyAll();
+ }
+
+ bool running_;
+ bool finished_;
+ ConditionVariable cv_;
+ Mutex mutex_;
+};
+
+} // namespace
+
+
+TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) {
+ static const int kThreadCount = 128;
+ ThreadWithMutexAndConditionVariable threads[kThreadCount];
+
+ for (int n = 0; n < kThreadCount; ++n) {
+ LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+ EXPECT_FALSE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ threads[n].Start();
+ // Wait for nth thread to start.
+ while (!threads[n].running_) {
+ threads[n].cv_.Wait(&threads[n].mutex_);
+ }
+ }
+
+ for (int n = kThreadCount - 1; n >= 0; --n) {
+ LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+ EXPECT_TRUE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ }
+
+ for (int n = 0; n < kThreadCount; ++n) {
+ LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+ EXPECT_TRUE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ // Tell the nth thread to quit.
+ threads[n].running_ = false;
+ threads[n].cv_.NotifyOne();
+ }
+
+ for (int n = kThreadCount - 1; n >= 0; --n) {
+ // Wait for nth thread to quit.
+ LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+ while (!threads[n].finished_) {
+ threads[n].cv_.Wait(&threads[n].mutex_);
+ }
+ EXPECT_FALSE(threads[n].running_);
+ EXPECT_TRUE(threads[n].finished_);
+ }
+
+ for (int n = 0; n < kThreadCount; ++n) {
+ threads[n].Join();
+ LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+ EXPECT_FALSE(threads[n].running_);
+ EXPECT_TRUE(threads[n].finished_);
+ }
+}
+
+
+namespace {
+
+class ThreadWithSharedMutexAndConditionVariable FINAL : public Thread {
+ public:
+ ThreadWithSharedMutexAndConditionVariable()
+ : Thread(Options("ThreadWithSharedMutexAndConditionVariable")),
+ running_(false),
+ finished_(false),
+ cv_(NULL),
+ mutex_(NULL) {}
+ virtual ~ThreadWithSharedMutexAndConditionVariable() {}
+
+ virtual void Run() OVERRIDE {
+ LockGuard<Mutex> lock_guard(mutex_);
+ running_ = true;
+ cv_->NotifyAll();
+ while (running_) {
+ cv_->Wait(mutex_);
+ }
+ finished_ = true;
+ cv_->NotifyAll();
+ }
+
+ bool running_;
+ bool finished_;
+ ConditionVariable* cv_;
+ Mutex* mutex_;
+};
+
+} // namespace
+
+
+TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) {
+ static const int kThreadCount = 128;
+ ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
+ ConditionVariable cv;
+ Mutex mutex;
+
+ for (int n = 0; n < kThreadCount; ++n) {
+ threads[n].mutex_ = &mutex;
+ threads[n].cv_ = &cv;
+ }
+
+ // Start all threads.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = 0; n < kThreadCount; ++n) {
+ EXPECT_FALSE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ threads[n].Start();
+ }
+ }
+
+ // Wait for all threads to start.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = kThreadCount - 1; n >= 0; --n) {
+ while (!threads[n].running_) {
+ cv.Wait(&mutex);
+ }
+ }
+ }
+
+ // Make sure that all threads are running.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = 0; n < kThreadCount; ++n) {
+ EXPECT_TRUE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ }
+ }
+
+ // Tell all threads to quit.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = kThreadCount - 1; n >= 0; --n) {
+ EXPECT_TRUE(threads[n].running_);
+ EXPECT_FALSE(threads[n].finished_);
+ // Tell the nth thread to quit.
+ threads[n].running_ = false;
+ }
+ cv.NotifyAll();
+ }
+
+ // Wait for all threads to quit.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = 0; n < kThreadCount; ++n) {
+ while (!threads[n].finished_) {
+ cv.Wait(&mutex);
+ }
+ }
+ }
+
+ // Make sure all threads are finished.
+ {
+ LockGuard<Mutex> lock_guard(&mutex);
+ for (int n = kThreadCount - 1; n >= 0; --n) {
+ EXPECT_FALSE(threads[n].running_);
+ EXPECT_TRUE(threads[n].finished_);
+ }
+ }
+
+ // Join all threads.
+ for (int n = 0; n < kThreadCount; ++n) {
+ threads[n].Join();
+ }
+}
+
+
+namespace {
+
+class LoopIncrementThread FINAL : public Thread {
+ public:
+ LoopIncrementThread(int rem, int* counter, int limit, int thread_count,
+ ConditionVariable* cv, Mutex* mutex)
+ : Thread(Options("LoopIncrementThread")),
+ rem_(rem),
+ counter_(counter),
+ limit_(limit),
+ thread_count_(thread_count),
+ cv_(cv),
+ mutex_(mutex) {
+ EXPECT_LT(rem, thread_count);
+ EXPECT_EQ(0, limit % thread_count);
+ }
+
+ virtual void Run() OVERRIDE {
+ int last_count = -1;
+ while (true) {
+ LockGuard<Mutex> lock_guard(mutex_);
+ int count = *counter_;
+ while (count % thread_count_ != rem_ && count < limit_) {
+ cv_->Wait(mutex_);
+ count = *counter_;
+ }
+ if (count >= limit_) break;
+ EXPECT_EQ(*counter_, count);
+ if (last_count != -1) {
+ EXPECT_EQ(last_count + (thread_count_ - 1), count);
+ }
+ count++;
+ *counter_ = count;
+ last_count = count;
+ cv_->NotifyAll();
+ }
+ }
+
+ private:
+ const int rem_;
+ int* counter_;
+ const int limit_;
+ const int thread_count_;
+ ConditionVariable* cv_;
+ Mutex* mutex_;
+};
+
+} // namespace
+
+
+TEST(ConditionVariable, LoopIncrement) {
+ static const int kMaxThreadCount = 16;
+ Mutex mutex;
+ ConditionVariable cv;
+ for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
+ int limit = thread_count * 10;
+ int counter = 0;
+
+ // Setup the threads.
+ Thread** threads = new Thread* [thread_count];
+ for (int n = 0; n < thread_count; ++n) {
+ threads[n] = new LoopIncrementThread(n, &counter, limit, thread_count,
+ &cv, &mutex);
+ }
+
+ // Start all threads.
+ for (int n = thread_count - 1; n >= 0; --n) {
+ threads[n]->Start();
+ }
+
+ // Join and cleanup all threads.
+ for (int n = 0; n < thread_count; ++n) {
+ threads[n]->Join();
+ delete threads[n];
+ }
+ delete[] threads;
+
+ EXPECT_EQ(limit, counter);
+ }
+}
+
+} // namespace base
+} // namespace v8