f64946a556138500880f12684e0321802accf86f
[model-checker-benchmarks.git] / spsc-queue / eventcount.h
1 #include <unrelacy.h>
2
3 class eventcount
4 {
5 public:
6         eventcount()
7                 : count(0)
8                 , waiters(0)
9         {}
10
11         void signal_relaxed()
12         {
13                 unsigned cmp = count.load(std::memory_order_relaxed);
14                 signal_impl(cmp);
15         }
16
17         void signal()
18         {
19                 unsigned cmp = count.fetch_add(0, std::memory_order_seq_cst);
20                 signal_impl(cmp);
21         }
22
23         unsigned get()
24         {
25                 unsigned cmp = count.fetch_or(0x80000000,
26 std::memory_order_seq_cst);
27                 return cmp & 0x7FFFFFFF;
28         }
29
30         void wait(unsigned cmp)
31         {
32                 unsigned ec = count.load(std::memory_order_seq_cst);
33                 if (cmp == (ec & 0x7FFFFFFF))
34                 {
35                         guard.lock($);
36                         ec = count.load(std::memory_order_seq_cst);
37                         if (cmp == (ec & 0x7FFFFFFF))
38                         {
39                                 waiters += 1;
40                                 cv.wait(guard, $);
41                         }
42                         guard.unlock($);
43                 }
44         }
45
46 private:
47         std::atomic<unsigned> count;
48         rl::var<unsigned> waiters;
49         mutex guard;
50         condition_variable_any cv;
51
52         void signal_impl(unsigned cmp)
53         {
54                 if (cmp & 0x80000000)
55                 {
56                         guard.lock($);
57                         while (false == count.compare_swap(cmp,
58                                 (cmp + 1) & 0x7FFFFFFF, std::memory_order_relaxed));
59                         unsigned w = waiters($);
60                         waiters = 0;
61                         guard.unlock($);
62                         if (w)
63                                 cv.notify_all($);
64                 }
65         }
66 };