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