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