| // 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_ |