summaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/heap/barrier-unittest.cc
blob: 1d42f97a4f3ae6cdf75af2a92bec45fd9fee2310 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
143
144
145
// Copyright 2017 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 "src/heap/barrier.h"
#include "src/base/platform/platform.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace v8 {
namespace internal {
namespace heap {

TEST(OneshotBarrier, InitializeNotDone) {
  OneshotBarrier barrier;
  EXPECT_FALSE(barrier.DoneForTesting());
}

TEST(OneshotBarrier, DoneAfterWait_Sequential) {
  OneshotBarrier barrier;
  barrier.Start();
  barrier.Wait();
  EXPECT_TRUE(barrier.DoneForTesting());
}

namespace {

class ThreadWaitingOnBarrier final : public base::Thread {
 public:
  ThreadWaitingOnBarrier()
      : base::Thread(Options("ThreadWaitingOnBarrier")), barrier_(nullptr) {}

  void Initialize(OneshotBarrier* barrier) { barrier_ = barrier; }

  void Run() final { barrier_->Wait(); }

 private:
  OneshotBarrier* barrier_;
};

}  // namespace

TEST(OneshotBarrier, DoneAfterWait_Concurrent) {
  const int kThreadCount = 2;
  OneshotBarrier barrier;
  ThreadWaitingOnBarrier threads[kThreadCount];
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Initialize(&barrier);
    // All threads need to call Wait() to be done.
    barrier.Start();
  }
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Start();
  }
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Join();
  }
  EXPECT_TRUE(barrier.DoneForTesting());
}

TEST(OneshotBarrier, EarlyFinish_Concurrent) {
  const int kThreadCount = 2;
  OneshotBarrier barrier;
  ThreadWaitingOnBarrier threads[kThreadCount];
  // Test that one thread that actually finishes processing work before other
  // threads call Start() will move the barrier in Done state.
  barrier.Start();
  barrier.Wait();
  EXPECT_TRUE(barrier.DoneForTesting());
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Initialize(&barrier);
    // All threads need to call Wait() to be done.
    barrier.Start();
  }
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Start();
  }
  for (int i = 0; i < kThreadCount; i++) {
    threads[i].Join();
  }
  EXPECT_TRUE(barrier.DoneForTesting());
}

namespace {

class CountingThread final : public base::Thread {
 public:
  CountingThread(OneshotBarrier* barrier, base::Mutex* mutex, size_t* work)
      : base::Thread(Options("CountingThread")),
        barrier_(barrier),
        mutex_(mutex),
        work_(work),
        processed_work_(0) {}

  void Run() final {
    do {
      ProcessWork();
    } while (!barrier_->Wait());
    // Main thread is not processing work, so we need one last step.
    ProcessWork();
  }

  size_t processed_work() const { return processed_work_; }

 private:
  void ProcessWork() {
    base::LockGuard<base::Mutex> guard(mutex_);
    processed_work_ += *work_;
    *work_ = 0;
  }

  OneshotBarrier* const barrier_;
  base::Mutex* const mutex_;
  size_t* const work_;
  size_t processed_work_;
};

}  // namespace

TEST(OneshotBarrier, Processing_Concurrent) {
  const size_t kWorkCounter = 173173;
  OneshotBarrier barrier;
  base::Mutex mutex;
  size_t work = 0;
  CountingThread counting_thread(&barrier, &mutex, &work);
  barrier.Start();
  barrier.Start();
  EXPECT_FALSE(barrier.DoneForTesting());
  counting_thread.Start();

  for (size_t i = 0; i < kWorkCounter; i++) {
    {
      base::LockGuard<base::Mutex> guard(&mutex);
      work++;
    }
    barrier.NotifyAll();
  }
  barrier.Wait();
  counting_thread.Join();
  EXPECT_TRUE(barrier.DoneForTesting());
  EXPECT_EQ(kWorkCounter, counting_thread.processed_work());
}

}  // namespace heap
}  // namespace internal
}  // namespace v8