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