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