hmbdc
simplify-high-performance-messaging-programming
PoolConsumer.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/pattern/LockFreeBufferMisc.hpp"
5 #include "hmbdc/time/Timers.hpp"
6 #include "hmbdc/Exception.hpp"
7 #include "hmbdc/Config.hpp"
8 #include <boost/smart_ptr/detail/yield_k.hpp>
9 #include <limits>
10 #include <iostream>
11 
12 #include <stdexcept>
13 
14 namespace hmbdc { namespace pattern {
15 
16 struct PoolConsumer {
17  friend struct PoolImpl;
18 
19  template <typename Buffer>
20  friend struct PoolTImpl;
21  friend struct PoolMinusImpl;
22  PoolConsumer(bool interestedInMessages, time::TimerManager* tmPtr, size_t* pDispStartCount);
23  virtual ~PoolConsumer();
24  void stopped(std::exception const&) noexcept;
25  bool dropped() noexcept;
26  void messageDispatchingStarted() {
27  if (hmbdc_unlikely(!messageDispatchingStarted_)) {
28  messageDispatchingStartedCb(pDispStartCount_
29  ?(__atomic_add_fetch(pDispStartCount_, 1, __ATOMIC_RELEASE), pDispStartCount_)
30  :0);
31  messageDispatchingStarted_ = true;
32  }
33  }
34  void invoked(size_t);
35 
36 protected:
38 
39 private:
40  void reset();
41  bool handleRange(BufIt begin,
42  BufIt end, uint16_t threadId) noexcept;
43  bool handleInvokeOnly(uint16_t threadId) noexcept;
44  virtual void messageDispatchingStartedCb(size_t const*) {}
45  virtual size_t handleRangeImpl(BufIt begin,
46  BufIt end, uint16_t threadId){ return 0; };
47  virtual void invokedCb(size_t) {}
48  virtual void stoppedCb(std::exception const&) {}
49  virtual bool droppedCb() { return true; }
50 
52  uint64_t poolThreadAffinity;
53  uint16_t droppedCount;
54  uint64_t skippedPoolThreadMask_;
55  HMBDC_SEQ_TYPE nextSeq_ __attribute__((__aligned__(SMP_CACHE_BYTES)));
56  bool interestedInMessages;
57  bool messageDispatchingStarted_;
58  size_t* pDispStartCount_ = nullptr;
59 };
60 
61 }} // end namespace hmbdc::pattern
62 
63 
64 namespace hmbdc { namespace pattern {
65 
66 inline
67 PoolConsumer::
68 PoolConsumer(bool interestedInMessages, time::TimerManager* tmPtr, size_t* pDispStartCount)
69 : tmPtr(tmPtr)
70 , poolThreadAffinity(0xfffffffffffffffful)
71 , droppedCount(0u)
72 , nextSeq_(std::numeric_limits<typename BufIt::Sequence>::max())
73 , interestedInMessages(interestedInMessages)
74 , messageDispatchingStarted_(false)
75 , pDispStartCount_(pDispStartCount) {
76 }
77 
78 inline
79 void
80 PoolConsumer::
81 reset() {
82  poolThreadAffinity = 0xfffffffffffffffful;
83  droppedCount = 0u;
84  nextSeq_ = std::numeric_limits<uint64_t>::max();
85 }
86 
87 inline
88 PoolConsumer::
89 ~PoolConsumer(){
90 }
91 
92 inline
93 void
94 PoolConsumer::
95 invoked(size_t n) {
96  if (tmPtr) {
97  tmPtr->checkTimers(time::SysTime::now());
98  }
99  invokedCb(n);
100 }
101 
102 inline
103 bool
104 PoolConsumer::
105 handleRange(BufIt begin,
106  BufIt end, uint16_t threadId) HMBDC_RESTRICT noexcept {
107  const auto STOP = std::numeric_limits<typename BufIt::Sequence>::max() - 1;
108  const auto IGNORE = std::numeric_limits<typename BufIt::Sequence>::max() - 2;
109  bool res = true;
110  if (hmbdc_unlikely(nextSeq_ == std::numeric_limits<typename BufIt::Sequence>::max()
111  && __sync_bool_compare_and_swap(&nextSeq_
112  , std::numeric_limits<typename BufIt::Sequence>::max(), begin.seq()))) {
113  try {
114  messageDispatchingStarted();
115  }
116  catch (std::exception const& e) {
117  nextSeq_ = STOP;
118  stopped(e);
119  res = false;
120  } catch (int c) {
121  nextSeq_ = STOP;
122  stopped(hmbdc::ExitCode(c));
123  res = false;
124  } catch (...) {
125  nextSeq_ = STOP;
126  stopped(hmbdc::UnknownException());
127  res = false;
128  }
129  }
130  auto nextSeq = nextSeq_;
131  if (hmbdc_unlikely(nextSeq == STOP)) return false;
132  else if (hmbdc_unlikely(nextSeq == IGNORE)) return true;
133  if ((hmbdc_unlikely(interestedInMessages && begin.seq() > nextSeq))) {
134  return true;
135  } else if (hmbdc_likely(end.seq() > nextSeq)) {
136  if (hmbdc_likely(__sync_bool_compare_and_swap(&nextSeq_, nextSeq, IGNORE))) {
137  try {
138  size_t res = 0;
139  if (hmbdc_likely(interestedInMessages)) {
140  PoolConsumer::BufIt myStart = begin + (size_t)(nextSeq - begin.seq());
141  res = handleRangeImpl(myStart, end, threadId);
142  }
143  invoked(res);
144  } catch (std::exception const& e) {
145  nextSeq_ = STOP;
146  stopped(e);
147  res = false;
148  } catch (int c) {
149  nextSeq_ = STOP;
150  stopped(hmbdc::ExitCode(c));
151  res = false;
152  } catch (...) {
153  nextSeq_ = STOP;
154  stopped(hmbdc::UnknownException());
155  res = false;
156  }
157  __sync_synchronize();
158  if (hmbdc_likely(res)) nextSeq_ = end.seq();
159  }
160  } else if (hmbdc_unlikely(!interestedInMessages
161  || (end.seq() == nextSeq && begin.seq() == nextSeq))) {
162  if (hmbdc_unlikely(__sync_bool_compare_and_swap(&nextSeq_, nextSeq, IGNORE))) {
163  try {
164  invoked(0);
165  } catch (std::exception const& e) {
166  nextSeq_ = STOP;
167  stopped(e);
168  res = false;
169  } catch (int c) {
170  nextSeq_ = STOP;
171  stopped(hmbdc::ExitCode(c));
172  res = false;
173  } catch (...) {
174  nextSeq_ = STOP;
175  stopped(hmbdc::UnknownException());
176  res = false;
177  }
178  __sync_synchronize();
179  if (hmbdc_likely(res)) nextSeq_ = end.seq();
180  }
181  }
182 
183  return res;
184 }
185 
186 inline
187 void
188 PoolConsumer::
189 stopped(std::exception const&e) noexcept {
190  try {
191  stoppedCb(e);
192  } catch (...) {}
193 }
194 
195 inline
196 bool
197 PoolConsumer::
198 dropped() noexcept {
199  bool res = true;
200  try {
201  res = droppedCb();
202  } catch (...) {}
203  return res;
204 }
205 
206 }} // end namespace hmbdc::pattern
Definition: TypedString.hpp:84
Definition: Timers.hpp:70
Unknown excpetion.
Definition: Exception.hpp:17
Definition: PoolConsumer.hpp:16
Definition: PoolT.ipp:25
Exception that just has an exit code.
Definition: Exception.hpp:28
Definition: PoolMinusImpl.hpp:24
Definition: Base.hpp:12
Definition: LockFreeBufferMisc.hpp:89