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:
ProducerThread(char * buffer,Semaphore * free_space,Semaphore * used_space)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 
Run()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:
ConsumerThread(const char * buffer,Semaphore * free_space,Semaphore * used_space)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 
Run()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:
WaitAndSignalThread(Semaphore * semaphore)72   explicit WaitAndSignalThread(Semaphore* semaphore)
73       : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {}
74 
Run()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 
TEST(Semaphore,ProducerConsumer)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 
TEST(Semaphore,WaitAndSignal)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 
TEST(Semaphore,WaitFor)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