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 
12 namespace v8 {
13 namespace 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.
37 class OneshotBarrier {
38  public:
OneshotBarrier(base::TimeDelta timeout)39   explicit OneshotBarrier(base::TimeDelta timeout) : timeout_(timeout) {}
40 
Start()41   void Start() {
42     base::MutexGuard guard(&mutex_);
43     tasks_++;
44   }
45 
NotifyAll()46   void NotifyAll() {
47     base::MutexGuard guard(&mutex_);
48     if (waiting_ > 0) condition_.NotifyAll();
49   }
50 
Wait()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.
DoneForTesting()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