add spsc for inference
[model-checker-benchmarks.git] / spsc-queue-scfence / eventcount.h
1 #include <unrelacy.h>
2 #include <atomic>
3 #include <mutex>
4 #include <condition_variable>
5 #include "wildcard.h" 
6
7 class eventcount
8 {
9 public:
10         eventcount() : waiters(0)
11         {
12                 count = 0;
13         }
14
15         void signal_relaxed()
16         {
17                 unsigned cmp = count.load(wildcard(1)); // relaxed
18                 signal_impl(cmp);
19         }
20
21         void signal()
22         {
23                 unsigned cmp = count.fetch_add(0, std::memory_order_seq_cst); // the fix
24                 signal_impl(cmp);
25         }
26
27         unsigned get()
28         {
29                 unsigned cmp = count.fetch_or(0x80000000, wildcard(2)); // sc
30                 return cmp & 0x7FFFFFFF;
31         }
32
33         void wait(unsigned cmp)
34         {
35                 unsigned ec = count.load(wildcard(3)); // sc
36                 if (cmp == (ec & 0x7FFFFFFF))
37                 {
38                         guard.lock($);
39                         ec = count.load(wildcard(4)); // sc
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, wildcard(5))); // relaxed
62                         unsigned w = waiters($);
63                         waiters = 0;
64                         guard.unlock($);
65                         if (w)
66                                 cv.notify_all($);
67                 }
68         }
69 };