hmbdc
simplify-high-performance-messaging-programming
SeqArb.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 
5 #include "hmbdc/Exception.hpp"
6 #include "hmbdc/Compile.hpp"
7 #include "hmbdc/Config.hpp"
8 #include <stdexcept>
9 #include <utility>
10 #include <inttypes.h>
11 #include <limits>
12 
13 
14 namespace hmbdc { namespace pattern {
15 
16 namespace seqarb_detail {
17 namespace {
18 
19 template <bool THREADSAFE>
20 inline __attribute__ ((always_inline))
21 void
22 my__sync_synchronize() {
23  if (THREADSAFE) __sync_synchronize();
24 }
25 
26 template <bool THREADSAFE, typename T>
27 inline __attribute__ ((always_inline))
28 bool
29 my__sync_bool_compare_and_swap(volatile T* var, T compVal, T newVal) {
30  if (THREADSAFE) return __sync_bool_compare_and_swap(var, compVal, newVal);
31  if (*var == compVal) {
32  *var = newVal;
33  return true;
34  }
35  return false;
36 }
37 
38 template <bool THREADSAFE, typename T>
39 inline __attribute__ ((always_inline))
40 T
41 my__sync_val_compare_and_swap(volatile T* var, T compVal, T newVal) {
42  if (THREADSAFE) return __sync_val_compare_and_swap(var, compVal, newVal);
43  auto res = *var;
44  if (*var == compVal) {
45  *var = newVal;
46  }
47  return res;
48 }
49 }
50 
51 template <uint16_t PARTICIPANT_COUNT, typename Seq = uint64_t, bool THREADSAFE = true>
52 struct SeqArb {
53  explicit SeqArb(Seq startSeq = 0)
54  : missedInit_(~((1ul << PARTICIPANT_COUNT) - 1u))
55  , gapFuncLock_(true)
56  , seq_(startSeq) {
57  static_assert(PARTICIPANT_COUNT <= 64u, "too many participants");
58  }
59 
60  SeqArb(SeqArb const&) = delete;
61  SeqArb& operator = (SeqArb const&) = delete;
62 
63  template <typename HitFunc, typename GapFunc>
64  inline __attribute__ ((always_inline))
65  bool operator()(uint16_t participantIndex, Seq seq, HitFunc&& h, GapFunc&& g) HMBDC_RESTRICT {
66  j_[participantIndex].seq = seq;
67 
68  auto old = my__sync_val_compare_and_swap<THREADSAFE>(&seq_, seq, std::numeric_limits<Seq>::max());
69 
70  if (old == seq) {
71  h();
72  my__sync_synchronize<THREADSAFE>();
73  seq_ = seq + 1;
74  return true; //arbitrated (utilized or discarded)
75  } else if (old == std::numeric_limits<Seq>::max()) {
76  return false ;
77  } else if (seq < old) {
78  return true; //arbitrated (discard)
79  } else { //seq > old
80  auto low = jLow();
81  if (hmbdc_unlikely((low > old && seq_ == old &&
82  my__sync_bool_compare_and_swap<THREADSAFE>(&seq_, old, std::numeric_limits<Seq>::max())))) {
83  g(low - old);
84  my__sync_synchronize<THREADSAFE>();
85  seq_ = low;
86  }
87  return false; //cannot decide and ask me later
88  }
89  }
90 
91  template <typename SeqGen, typename HitFunc, typename GapFunc>
92  inline __attribute__ ((always_inline))
93  size_t operator()(uint16_t participantIndex, SeqGen&& seqGen
94  , size_t seqSize, HitFunc&& h, GapFunc&& g) HMBDC_RESTRICT {
95  auto seq = seqGen();
96  j_[participantIndex].seq = seq;
97 
98  auto old = my__sync_val_compare_and_swap<THREADSAFE>(
99  &seq_, seq, std::numeric_limits<Seq>::max());
100 
101  if (old == seq) {
102  h();
103  auto preSeq = seq;
104  auto s = 1ul;
105  for (; s < seqSize; ++s) {
106  seq = seqGen();
107  if (seq - 1 == preSeq) {
108  preSeq = seq;
109  h();
110  } else {
111  break;
112  }
113  }
114  j_[participantIndex].seq = seq;
115  my__sync_synchronize<THREADSAFE>();
116  seq_ = seq + s;
117  return s;
118  } else if (old == std::numeric_limits<Seq>::max()) {
119  return 0;
120  } else if (seq < old) {
121  return 1ul; //arbitrated (discard)
122  } else { //seq > old
123  auto low = jLow();
124  if (hmbdc_unlikely((low > old && seq_ == old &&
125  my__sync_bool_compare_and_swap<THREADSAFE>(
126  &seq_, old, std::numeric_limits<Seq>::max())))) {
127  g(low - old);
128  my__sync_synchronize<THREADSAFE>();
129  seq_ = low;
130  }
131  return 0; //cannot decide and ask me later
132  }
133  }
134 
135  volatile Seq const& expectingSeq() const {
136  return seq_;
137  }
138 
139  volatile Seq& expectingSeq() {
140  return seq_;
141  }
142 
143 private:
144  inline __attribute__ ((always_inline))
145  Seq jLow() const HMBDC_RESTRICT {
146  auto res = j_[0].seq;
147  for (auto i = 1u; i < PARTICIPANT_COUNT; ++i)
148  if (res > j_[i].seq) res = j_[i].seq;
149  return res;
150  }
151 
152  uint64_t const missedInit_;
153  bool gapFuncLock_;
154  volatile Seq seq_ __attribute__((__aligned__(SMP_CACHE_BYTES)));
155  uint64_t missed_ __attribute__((__aligned__(SMP_CACHE_BYTES)));
156  struct J {
157  J() : seq(0u){}
158  Seq seq;
159  } __attribute__((__aligned__(SMP_CACHE_BYTES)));
160  J j_[PARTICIPANT_COUNT];
161 };
162 
163 template <uint16_t PARTICIPANT_COUNT, typename Seq = uint64_t>
165  SingleThreadSeqArb(Seq startSeq = 0)
166  : arb_(startSeq){}
167 
168  template <typename GapFunc>
169  int operator()(uint16_t participantIndex, Seq seq, GapFunc&& gapFunc) {
170  int res = -1;
171  if (!arb_(participantIndex, seq
172  , [&res]() {
173  res = 1;
174  }
175  , std::forward<GapFunc>(gapFunc)
176  )
177  ) {
178  res = 0;
179  }
180  return res;
181  }
182 
183  volatile Seq& expectingSeq() {
184  return arb_.expectingSeq();
185  }
186 
187  volatile Seq const& expectingSeq() const {
188  return arb_.expectingSeq();
189  }
190 
191 private:
193 };
194 
195 } //seqarb_detail
196 
197 template <uint16_t PARTICIPANT_COUNT, typename Seq = uint64_t, bool THREADSAFE = true>
199 
200 template <uint16_t PARTICIPANT_COUNT, typename Seq = uint64_t>
202 
203 }}
Definition: SeqArb.hpp:52
Definition: Base.hpp:12