Line data Source code
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 26103 : class OneshotBarrier {
38 : public:
39 26103 : explicit OneshotBarrier(base::TimeDelta timeout) : timeout_(timeout) {}
40 :
41 : void Start() {
42 46649 : base::MutexGuard guard(&mutex_);
43 46742 : tasks_++;
44 : }
45 :
46 414065 : void NotifyAll() {
47 414065 : base::MutexGuard guard(&mutex_);
48 414271 : if (waiting_ > 0) condition_.NotifyAll();
49 414266 : }
50 :
51 47996 : bool Wait() {
52 47996 : base::MutexGuard guard(&mutex_);
53 48129 : if (done_) return true;
54 :
55 : DCHECK_LE(waiting_, tasks_);
56 34060 : waiting_++;
57 34060 : if (waiting_ == tasks_) {
58 25240 : done_ = true;
59 25240 : condition_.NotifyAll();
60 : } else {
61 : // Spurious wakeup is ok here.
62 8820 : if (!condition_.WaitFor(&mutex_, timeout_)) {
63 : // If predefined timeout was reached, Stop waiting and signal being done
64 : // also to other tasks.
65 2747 : done_ = true;
66 : }
67 : }
68 34060 : waiting_--;
69 34060 : 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_
|