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