semaphore-unittest.cc 3.58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstring>

#include "src/base/platform/platform.h"
#include "src/base/platform/semaphore.h"
#include "src/base/platform/time.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace v8 {
namespace base {

namespace {

static const char kAlphabet[] = "XKOAD";
static const size_t kAlphabetSize = sizeof(kAlphabet) - 1;
static const size_t kBufferSize = 987;  // GCD(buffer size, alphabet size) = 1
static const size_t kDataSize = kBufferSize * kAlphabetSize * 10;


23
class ProducerThread final : public Thread {
24 25 26 27 28 29 30
 public:
  ProducerThread(char* buffer, Semaphore* free_space, Semaphore* used_space)
      : Thread(Options("ProducerThread")),
        buffer_(buffer),
        free_space_(free_space),
        used_space_(used_space) {}

31
  void Run() override {
32 33 34 35 36 37 38 39 40 41 42 43 44 45
    for (size_t n = 0; n < kDataSize; ++n) {
      free_space_->Wait();
      buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize];
      used_space_->Signal();
    }
  }

 private:
  char* buffer_;
  Semaphore* const free_space_;
  Semaphore* const used_space_;
};


46
class ConsumerThread final : public Thread {
47 48 49 50 51 52 53 54
 public:
  ConsumerThread(const char* buffer, Semaphore* free_space,
                 Semaphore* used_space)
      : Thread(Options("ConsumerThread")),
        buffer_(buffer),
        free_space_(free_space),
        used_space_(used_space) {}

55
  void Run() override {
56 57 58 59 60 61 62 63 64 65 66 67 68 69
    for (size_t n = 0; n < kDataSize; ++n) {
      used_space_->Wait();
      EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]);
      free_space_->Signal();
    }
  }

 private:
  const char* buffer_;
  Semaphore* const free_space_;
  Semaphore* const used_space_;
};


70
class WaitAndSignalThread final : public Thread {
71 72 73 74
 public:
  explicit WaitAndSignalThread(Semaphore* semaphore)
      : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {}

75
  void Run() override {
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    for (int n = 0; n < 100; ++n) {
      semaphore_->Wait();
      ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1)));
      semaphore_->Signal();
    }
  }

 private:
  Semaphore* const semaphore_;
};

}  // namespace


TEST(Semaphore, ProducerConsumer) {
  char buffer[kBufferSize];
  std::memset(buffer, 0, sizeof(buffer));
  Semaphore free_space(kBufferSize);
  Semaphore used_space(0);
  ProducerThread producer_thread(buffer, &free_space, &used_space);
  ConsumerThread consumer_thread(buffer, &free_space, &used_space);
  producer_thread.Start();
  consumer_thread.Start();
  producer_thread.Join();
  consumer_thread.Join();
}


TEST(Semaphore, WaitAndSignal) {
  Semaphore semaphore(0);
  WaitAndSignalThread t1(&semaphore);
  WaitAndSignalThread t2(&semaphore);

  t1.Start();
  t2.Start();

  // Make something available.
  semaphore.Signal();

  t1.Join();
  t2.Join();

  semaphore.Wait();

  EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1)));
}


TEST(Semaphore, WaitFor) {
  Semaphore semaphore(0);

  // Semaphore not signalled - timeout.
  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));

  // Semaphore signalled - no timeout.
  semaphore.Signal();
  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
  semaphore.Signal();
  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
  semaphore.Signal();
  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));
}

}  // namespace base
}  // namespace v8