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