• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
15 class 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:
AutoResetEvent()24   AutoResetEvent() : status_(0), semaphore_(0) {}
25 
Signal()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 
Wait()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