// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can // be found in the LICENSE file. #ifndef UTIL_AUTO_RESET_EVENT_H_ #define UTIL_AUTO_RESET_EVENT_H_ #include #include "base/logging.h" #include "util/semaphore.h" // From http://preshing.com/20150316/semaphores-are-surprisingly-versatile/, // but using V8's Semaphore. class AutoResetEvent { private: // status_ == 1: Event object is signaled. // status_ == 0: Event object is reset and no threads are waiting. // status_ == -N: Event object is reset and N threads are waiting. std::atomic status_; Semaphore semaphore_; public: AutoResetEvent() : status_(0), semaphore_(0) {} void Signal() { int old_status = status_.load(std::memory_order_relaxed); // Increment status_ atomically via CAS loop. for (;;) { DCHECK_LE(old_status, 1); int new_status = old_status < 1 ? old_status + 1 : 1; if (status_.compare_exchange_weak(old_status, new_status, std::memory_order_release, std::memory_order_relaxed)) { break; } // The compare-exchange failed, likely because another thread changed // status_. old_status has been updated. Retry the CAS loop. } if (old_status < 0) semaphore_.Signal(); // Release one waiting thread. } void Wait() { int old_status = status_.fetch_sub(1, std::memory_order_acquire); DCHECK_LE(old_status, 1); if (old_status < 1) { semaphore_.Wait(); } } }; #endif // UTIL_AUTO_RESET_EVENT_H_