1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can 3 // be found in the LICENSE file. 4 5 #ifndef UTIL_AUTO_RESET_EVENT_H_ 6 #define UTIL_AUTO_RESET_EVENT_H_ 7 8 #include <atomic> 9 10 #include "base/logging.h" 11 #include "util/semaphore.h" 12 13 // From http://preshing.com/20150316/semaphores-are-surprisingly-versatile/, 14 // but using V8's Semaphore. 15 class AutoResetEvent { 16 private: 17 // status_ == 1: Event object is signaled. 18 // status_ == 0: Event object is reset and no threads are waiting. 19 // status_ == -N: Event object is reset and N threads are waiting. 20 std::atomic<int> status_; 21 Semaphore semaphore_; 22 23 public: AutoResetEvent()24 AutoResetEvent() : status_(0), semaphore_(0) {} 25 Signal()26 void Signal() { 27 int old_status = status_.load(std::memory_order_relaxed); 28 // Increment status_ atomically via CAS loop. 29 for (;;) { 30 DCHECK_LE(old_status, 1); 31 int new_status = old_status < 1 ? old_status + 1 : 1; 32 if (status_.compare_exchange_weak(old_status, new_status, 33 std::memory_order_release, 34 std::memory_order_relaxed)) { 35 break; 36 } 37 // The compare-exchange failed, likely because another thread changed 38 // status_. old_status has been updated. Retry the CAS loop. 39 } 40 if (old_status < 0) 41 semaphore_.Signal(); // Release one waiting thread. 42 } 43 Wait()44 void Wait() { 45 int old_status = status_.fetch_sub(1, std::memory_order_acquire); 46 DCHECK_LE(old_status, 1); 47 if (old_status < 1) { 48 semaphore_.Wait(); 49 } 50 } 51 }; 52 53 #endif // UTIL_AUTO_RESET_EVENT_H_ 54