|  | // 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 <atomic> | 
|  |  | 
|  | #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<int> 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_ |