xref: /third_party/gn/src/util/auto_reset_event.h (revision 6d528ed9)
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