// 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 <cstring> #include "src/base/platform/platform.h" #include "src/base/platform/semaphore.h" #include "src/base/platform/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { namespace base { namespace { static const char kAlphabet[] = "XKOAD"; static const size_t kAlphabetSize = sizeof(kAlphabet) - 1; static const size_t kBufferSize = 987; // GCD(buffer size, alphabet size) = 1 static const size_t kDataSize = kBufferSize * kAlphabetSize * 10; class ProducerThread FINAL : public Thread { public: ProducerThread(char* buffer, Semaphore* free_space, Semaphore* used_space) : Thread(Options("ProducerThread")), buffer_(buffer), free_space_(free_space), used_space_(used_space) {} virtual ~ProducerThread() {} virtual void Run() OVERRIDE { for (size_t n = 0; n < kDataSize; ++n) { free_space_->Wait(); buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize]; used_space_->Signal(); } } private: char* buffer_; Semaphore* const free_space_; Semaphore* const used_space_; }; class ConsumerThread FINAL : public Thread { public: ConsumerThread(const char* buffer, Semaphore* free_space, Semaphore* used_space) : Thread(Options("ConsumerThread")), buffer_(buffer), free_space_(free_space), used_space_(used_space) {} virtual ~ConsumerThread() {} virtual void Run() OVERRIDE { for (size_t n = 0; n < kDataSize; ++n) { used_space_->Wait(); EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]); free_space_->Signal(); } } private: const char* buffer_; Semaphore* const free_space_; Semaphore* const used_space_; }; class WaitAndSignalThread FINAL : public Thread { public: explicit WaitAndSignalThread(Semaphore* semaphore) : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {} virtual ~WaitAndSignalThread() {} virtual void Run() OVERRIDE { for (int n = 0; n < 100; ++n) { semaphore_->Wait(); ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1))); semaphore_->Signal(); } } private: Semaphore* const semaphore_; }; } // namespace TEST(Semaphore, ProducerConsumer) { char buffer[kBufferSize]; std::memset(buffer, 0, sizeof(buffer)); Semaphore free_space(kBufferSize); Semaphore used_space(0); ProducerThread producer_thread(buffer, &free_space, &used_space); ConsumerThread consumer_thread(buffer, &free_space, &used_space); producer_thread.Start(); consumer_thread.Start(); producer_thread.Join(); consumer_thread.Join(); } TEST(Semaphore, WaitAndSignal) { Semaphore semaphore(0); WaitAndSignalThread t1(&semaphore); WaitAndSignalThread t2(&semaphore); t1.Start(); t2.Start(); // Make something available. semaphore.Signal(); t1.Join(); t2.Join(); semaphore.Wait(); EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1))); } TEST(Semaphore, WaitFor) { Semaphore semaphore(0); // Semaphore not signalled - timeout. ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); // Semaphore signalled - no timeout. semaphore.Signal(); ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); semaphore.Signal(); ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); semaphore.Signal(); ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); } } // namespace base } // namespace v8