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