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 11 namespace v8 { 12 namespace internal { 13 14 // Barrier that can be used once to synchronize a dynamic number of tasks 15 // working concurrently. 16 // 17 // Usage: 18 // void RunConcurrently(OneShotBarrier* shared_barrier) { 19 // shared_barrier->Start(); 20 // do { 21 // { 22 // /* process work and create new work */ 23 // barrier->NotifyAll(); 24 // /* process work and create new work */ 25 // } 26 // } while(!shared_barrier->Wait()); 27 // } 28 // 29 // Note: If Start() is not called in time, e.g., because the first concurrent 30 // task is already done processing all work, then Done() will return true 31 // immediately. 32 class OneshotBarrier { 33 public: OneshotBarrier()34 OneshotBarrier() : tasks_(0), waiting_(0), done_(false) {} 35 Start()36 void Start() { 37 base::LockGuard<base::Mutex> guard(&mutex_); 38 tasks_++; 39 } 40 NotifyAll()41 void NotifyAll() { 42 base::LockGuard<base::Mutex> guard(&mutex_); 43 if (waiting_ > 0) condition_.NotifyAll(); 44 } 45 Wait()46 bool Wait() { 47 base::LockGuard<base::Mutex> guard(&mutex_); 48 if (done_) return true; 49 50 DCHECK_LE(waiting_, tasks_); 51 waiting_++; 52 if (waiting_ == tasks_) { 53 done_ = true; 54 condition_.NotifyAll(); 55 } else { 56 // Spurious wakeup is ok here. 57 condition_.Wait(&mutex_); 58 } 59 waiting_--; 60 return done_; 61 } 62 63 // Only valid to be called in a sequential setting. DoneForTesting()64 bool DoneForTesting() const { return done_; } 65 66 private: 67 base::ConditionVariable condition_; 68 base::Mutex mutex_; 69 int tasks_; 70 int waiting_; 71 bool done_; 72 }; 73 74 } // namespace internal 75 } // namespace v8 76 77 #endif // V8_HEAP_BARRIER_H_ 78