1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <cstring> 6 7#include "src/base/platform/platform.h" 8#include "src/base/platform/semaphore.h" 9#include "src/base/platform/time.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12namespace v8 { 13namespace base { 14 15namespace { 16 17static const char kAlphabet[] = "XKOAD"; 18static const size_t kAlphabetSize = sizeof(kAlphabet) - 1; 19static const size_t kBufferSize = 987; // GCD(buffer size, alphabet size) = 1 20static const size_t kDataSize = kBufferSize * kAlphabetSize * 10; 21 22 23class ProducerThread FINAL : public Thread { 24 public: 25 ProducerThread(char* buffer, Semaphore* free_space, Semaphore* used_space) 26 : Thread(Options("ProducerThread")), 27 buffer_(buffer), 28 free_space_(free_space), 29 used_space_(used_space) {} 30 virtual ~ProducerThread() {} 31 32 virtual void Run() OVERRIDE { 33 for (size_t n = 0; n < kDataSize; ++n) { 34 free_space_->Wait(); 35 buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize]; 36 used_space_->Signal(); 37 } 38 } 39 40 private: 41 char* buffer_; 42 Semaphore* const free_space_; 43 Semaphore* const used_space_; 44}; 45 46 47class ConsumerThread FINAL : public Thread { 48 public: 49 ConsumerThread(const char* buffer, Semaphore* free_space, 50 Semaphore* used_space) 51 : Thread(Options("ConsumerThread")), 52 buffer_(buffer), 53 free_space_(free_space), 54 used_space_(used_space) {} 55 virtual ~ConsumerThread() {} 56 57 virtual void Run() OVERRIDE { 58 for (size_t n = 0; n < kDataSize; ++n) { 59 used_space_->Wait(); 60 EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]); 61 free_space_->Signal(); 62 } 63 } 64 65 private: 66 const char* buffer_; 67 Semaphore* const free_space_; 68 Semaphore* const used_space_; 69}; 70 71 72class WaitAndSignalThread FINAL : public Thread { 73 public: 74 explicit WaitAndSignalThread(Semaphore* semaphore) 75 : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {} 76 virtual ~WaitAndSignalThread() {} 77 78 virtual void Run() OVERRIDE { 79 for (int n = 0; n < 100; ++n) { 80 semaphore_->Wait(); 81 ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1))); 82 semaphore_->Signal(); 83 } 84 } 85 86 private: 87 Semaphore* const semaphore_; 88}; 89 90} // namespace 91 92 93TEST(Semaphore, ProducerConsumer) { 94 char buffer[kBufferSize]; 95 std::memset(buffer, 0, sizeof(buffer)); 96 Semaphore free_space(kBufferSize); 97 Semaphore used_space(0); 98 ProducerThread producer_thread(buffer, &free_space, &used_space); 99 ConsumerThread consumer_thread(buffer, &free_space, &used_space); 100 producer_thread.Start(); 101 consumer_thread.Start(); 102 producer_thread.Join(); 103 consumer_thread.Join(); 104} 105 106 107TEST(Semaphore, WaitAndSignal) { 108 Semaphore semaphore(0); 109 WaitAndSignalThread t1(&semaphore); 110 WaitAndSignalThread t2(&semaphore); 111 112 t1.Start(); 113 t2.Start(); 114 115 // Make something available. 116 semaphore.Signal(); 117 118 t1.Join(); 119 t2.Join(); 120 121 semaphore.Wait(); 122 123 EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1))); 124} 125 126 127TEST(Semaphore, WaitFor) { 128 Semaphore semaphore(0); 129 130 // Semaphore not signalled - timeout. 131 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); 132 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); 133 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); 134 135 // Semaphore signalled - no timeout. 136 semaphore.Signal(); 137 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); 138 semaphore.Signal(); 139 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); 140 semaphore.Signal(); 141 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); 142} 143 144} // namespace base 145} // namespace v8 146