1// Copyright 2017 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#ifndef V8_HEAP_BARRIER_H_
6#define V8_HEAP_BARRIER_H_
7
8#include "src/base/platform/condition-variable.h"
9#include "src/base/platform/mutex.h"
10#include "src/base/platform/time.h"
11
12namespace v8 {
13namespace internal {
14
15// Barrier that can be used once to synchronize a dynamic number of tasks
16// working concurrently.
17//
18// The barrier takes a timeout which is used to avoid waiting for too long. If
19// any of the users ever reach the timeout they will disable the barrier and
20// signal others to fall through.
21//
22// Usage:
23// void RunConcurrently(OneShotBarrier* shared_barrier) {
24// shared_barrier->Start();
25// do {
26// {
27// /* process work and create new work */
28// barrier->NotifyAll();
29// /* process work and create new work */
30// }
31// } while(!shared_barrier->Wait());
32// }
33//
34// Note: If Start() is not called in time, e.g., because the first concurrent
35// task is already done processing all work, then Done() will return true
36// immediately.
37class OneshotBarrier {
38 public:
39 explicit OneshotBarrier(base::TimeDelta timeout) : timeout_(timeout) {}
40
41 void Start() {
42 base::MutexGuard guard(&mutex_);
43 tasks_++;
44 }
45
46 void NotifyAll() {
47 base::MutexGuard guard(&mutex_);
48 if (waiting_ > 0) condition_.NotifyAll();
49 }
50
51 bool Wait() {
52 base::MutexGuard guard(&mutex_);
53 if (done_) return true;
54
55 DCHECK_LE(waiting_, tasks_);
56 waiting_++;
57 if (waiting_ == tasks_) {
58 done_ = true;
59 condition_.NotifyAll();
60 } else {
61 // Spurious wakeup is ok here.
62 if (!condition_.WaitFor(&mutex_, timeout_)) {
63 // If predefined timeout was reached, Stop waiting and signal being done
64 // also to other tasks.
65 done_ = true;
66 }
67 }
68 waiting_--;
69 return done_;
70 }
71
72 // Only valid to be called in a sequential setting.
73 bool DoneForTesting() const { return done_; }
74
75 private:
76 base::ConditionVariable condition_;
77 base::Mutex mutex_;
78 base::TimeDelta timeout_;
79 int tasks_ = 0;
80 int waiting_ = 0;
81 bool done_ = false;
82};
83
84} // namespace internal
85} // namespace v8
86
87#endif // V8_HEAP_BARRIER_H_
88