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 12 namespace v8 { 13 namespace base { 14 15 namespace { 16 17 static const char kAlphabet[] = "XKOAD"; 18 static const size_t kAlphabetSize = sizeof(kAlphabet) - 1; 19 static const size_t kBufferSize = 987; // GCD(buffer size, alphabet size) = 1 20 static const size_t kDataSize = kBufferSize * kAlphabetSize * 10; 21 22 23 class 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 31 void Run() override { 32 for (size_t n = 0; n < kDataSize; ++n) { 33 free_space_->Wait(); 34 buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize]; 35 used_space_->Signal(); 36 } 37 } 38 39 private: 40 char* buffer_; 41 Semaphore* const free_space_; 42 Semaphore* const used_space_; 43 }; 44 45 46 class ConsumerThread final : public Thread { 47 public: 48 ConsumerThread(const char* buffer, Semaphore* free_space, 49 Semaphore* used_space) 50 : Thread(Options("ConsumerThread")), 51 buffer_(buffer), 52 free_space_(free_space), 53 used_space_(used_space) {} 54 55 void Run() override { 56 for (size_t n = 0; n < kDataSize; ++n) { 57 used_space_->Wait(); 58 EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]); 59 free_space_->Signal(); 60 } 61 } 62 63 private: 64 const char* buffer_; 65 Semaphore* const free_space_; 66 Semaphore* const used_space_; 67 }; 68 69 70 class WaitAndSignalThread final : public Thread { 71 public: 72 explicit WaitAndSignalThread(Semaphore* semaphore) 73 : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {} 74 75 void Run() override { 76 for (int n = 0; n < 100; ++n) { 77 semaphore_->Wait(); 78 ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1))); 79 semaphore_->Signal(); 80 } 81 } 82 83 private: 84 Semaphore* const semaphore_; 85 }; 86 87 } // namespace 88 89 90 TEST(Semaphore, ProducerConsumer) { 91 char buffer[kBufferSize]; 92 std::memset(buffer, 0, sizeof(buffer)); 93 Semaphore free_space(kBufferSize); 94 Semaphore used_space(0); 95 ProducerThread producer_thread(buffer, &free_space, &used_space); 96 ConsumerThread consumer_thread(buffer, &free_space, &used_space); 97 producer_thread.Start(); 98 consumer_thread.Start(); 99 producer_thread.Join(); 100 consumer_thread.Join(); 101 } 102 103 104 TEST(Semaphore, WaitAndSignal) { 105 Semaphore semaphore(0); 106 WaitAndSignalThread t1(&semaphore); 107 WaitAndSignalThread t2(&semaphore); 108 109 t1.Start(); 110 t2.Start(); 111 112 // Make something available. 113 semaphore.Signal(); 114 115 t1.Join(); 116 t2.Join(); 117 118 semaphore.Wait(); 119 120 EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1))); 121 } 122 123 124 TEST(Semaphore, WaitFor) { 125 Semaphore semaphore(0); 126 127 // Semaphore not signalled - timeout. 128 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); 129 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); 130 ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); 131 132 // Semaphore signalled - no timeout. 133 semaphore.Signal(); 134 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0))); 135 semaphore.Signal(); 136 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100))); 137 semaphore.Signal(); 138 ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000))); 139 } 140 141 } // namespace base 142 } // namespace v8 143