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 23495 : class OneshotBarrier {
38 : public:
39 23495 : explicit OneshotBarrier(base::TimeDelta timeout) : timeout_(timeout) {}
40 :
41 37530 : void Start() {
42 37530 : base::MutexGuard guard(&mutex_);
43 37591 : tasks_++;
44 37584 : }
45 :
46 433364 : void NotifyAll() {
47 433364 : base::MutexGuard guard(&mutex_);
48 433490 : if (waiting_ > 0) condition_.NotifyAll();
49 433488 : }
50 :
51 38209 : bool Wait() {
52 38209 : base::MutexGuard guard(&mutex_);
53 38247 : if (done_) return true;
54 :
55 : DCHECK_LE(waiting_, tasks_);
56 27927 : waiting_++;
57 27927 : if (waiting_ == tasks_) {
58 22719 : done_ = true;
59 22719 : condition_.NotifyAll();
60 : } else {
61 : // Spurious wakeup is ok here.
62 5208 : if (!condition_.WaitFor(&mutex_, timeout_)) {
63 : // If predefined timeout was reached, Stop waiting and signal being done
64 : // also to other tasks.
65 2398 : done_ = true;
66 : }
67 : }
68 27927 : waiting_--;
69 27927 : 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_
|