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. 15class 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: 24 AutoResetEvent() : status_(0), semaphore_(0) {} 25 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 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