hmbdc
simplify-high-performance-messaging-programming
Client.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/app/MessageDispacher.hpp"
5 #include "hmbdc/MetaUtils.hpp"
6 #include "hmbdc/Compile.hpp"
7 
8 #include <iostream>
9 #include <tuple>
10 #include <type_traits>
11 
12 namespace hmbdc { namespace app {
13 
14 /**
15  * @class single_thread_powered_client
16  * @brief a trait class, if a Client can only run on a single specific thread in Pool,
17  * derive the Client from it, hmbdc will check to ensure that is the case
18  */
20 
21 /**
22  * @class Client<>
23  * @brief A Client represents a thread of execution/a task. The execution is managed by
24  * a Context.
25  * a Client object could participate in message dispatching as the receiver of specifed
26  * message types
27  * @details message is dispatched thru callbacks in the loose
28  * form of void handleMessageCb(Message const& m) or void handleMessageCb(Message& m).
29  * some callbacks have default implementations.
30  * however, all callbacks are overridable to provide desired effects;
31  * When running in a Context, all callbacks (*Cb methods) for a hmbdc Client instance
32  * are garanteed to be called from a single OS thread, ie. no 2 callabacks of an Client
33  * instance are called concurrently, so the Client programmer can assume a
34  * single thread programming model callback-wise.
35  * The above also holds true for timer firing callbacks when a concrete Client deriving
36  * from TimerManager that manages the timers
37  *
38  * See in example hmbdc.cpp @snippet hmbdc.cpp write a Client
39  *
40  * @tparam CcClient the concrete Client type
41  * @tparam typename ... Messages message types that the Client interested
42  * if the type of JustBytes is declared, use a special callback see below
43  *
44  * @code
45  * void handleJustBytesCb(uint16_t tag, uint8_t* bytes){...}
46  * @endcode
47  * is expected
48  * see ConsoleClient.hpp
49  *
50  * There are 3 categories of Messages can be specified here regular, REQUEST, REPLY
51  * REQUEST, REPLY are for synchronous request reply messages, this is like
52  * remote procedure call (RPC) function except it is more powerful that it gives
53  * more flexible forms of RPC returning behavior - see requestReply() sendReply()
54  * in Context.hpp, and RequestReply.hpp for details
55  */
56 template <typename CcClient, MessageC ... Messages>
57 struct Client {
58  using Interests
59  = typename templatized_subtractor<REPLY, std::tuple<Messages ...>>::type;
60  using Requests
61  = typename templatized_aggregator<REQUEST, std::tuple<Messages ...>>::type;
62  using Replies
63  = typename templatized_aggregator<REPLY, std::tuple<Messages ...>>::type;
64 
65  enum {
66  INTERESTS_SIZE = std::tuple_size<Interests>::value,
67  };
68  // static_assert(std::is_base_of<Client, CcClient>::value, "");
69 
70  /**
71  * @brief return the name of thread that runs this client, override if necessary
72  * @details this only used when the Client is running in direct mode
73  * @return thread name - default to be hmbdc0, hmbdc1 ...
74  */
75  char const* hmbdcName() const { return "hmbdc-anonymous"; }
76 
77  /**
78  * @brief an overrideable method.
79  * returns the schedule policy and priority, override if necessary
80  * priority is only used when policy is "SCHED_RR", or "SCHED_FIFO"
81  * @details this is only used when the Client is running in direct mode
82  * supported policy are "SCHED_OTHER"(=nullptr), "SCHED_RR", "SCHED_FIFO"
83  * @return a tuple made of schedule policy and priority, default to be SCHED_OTHER
84  */
85  std::tuple<char const*, int> schedSpec() const {
86  return std::make_tuple<char const*, int>(nullptr, 0);
87  }
88 
89  /**
90  * @brief an overridable method.
91  * client receives events in batches and the max batch size is controllable when running
92  * in direct mode Context. Here is to specify the max size.
93  * @details a message could only be reaching one client when using partition Context. In this
94  * case, reduce the size (reduce the greediness) might be useful
95  * @return the max number of messages when grabbing messages to process
96  */
97  size_t maxBatchMessageCount() const {return std::numeric_limits<size_t>::max();}
98 
99 
100  /**
101  * @brief called before any messages got dispatched - only once
102  * @details this is the place some preparation code goes to
103  *
104  * @param threadSerialNumber normally the number
105  * indicating which thread is in action, except when INTERESTS_SIZE == 0
106  * it is another undefined value
107  *
108  */
109  virtual void messageDispatchingStartedCb(uint16_t threadSerialNumber) {
110  //default do nothing
111  };
112 
113  /**
114  * @brief callback called when this Client is taken out of message dispatching
115  * @details after this call the Client is still at hook from the Context point of view
116  * (until droppedCb is called), so don't delete this Client yet or add it back to
117  * the Context. any exception thrown here is ignored,
118  *
119  * @param e the exception that caused the Client to be taken out of message dispatching
120  * e could be thrown by the Client itself in a callback function
121  * to voluntarily take itself out
122  */
123  virtual void stoppedCb(std::exception const& e) {
124  // called when this client is stopped, e.what() might have reason
125  std::cerr << "Client " << hmbdcName()
126  << " exited with reason: " << e.what() << std::endl;
127  };
128 
129  /**
130  * @brief callback called after the Client is safely taken out of the Context
131  * @details exception thrown here is ignored and return true is assumed
132  * @return if false, this Client is added back to the Context to process messages
133  * otherwise, no more callback. You could even safely "delete this; return true;"
134  */
135  virtual bool droppedCb() {
136  // called when this client is dropped and free to be deleted
137  return true;
138  };
139 
140  /**
141  * @brief this callback is called all the time (frequently) - the exact timing is
142  * after a batch of messages are dispatched. After this call returns, the previously
143  * dispatched message's addresses are no longer valid, which means if you cache the
144  * event addresses in the previous handleMessageCb()s, you cannot use those after
145  * the return of the next invokeCb function.
146  * @details you can collectively process the messages received/cached so far here, or
147  * do something needs to be done all the time like powering another message loop
148  *
149  * @param threadSerialNumber the number
150  * indicating which thread is in action
151  */
152  virtual void invokedCb(uint16_t threadSerialNumber) {
153  // called as frequently as workload allowed
154  }
155 
156  /**
157  * @brief trivial
158  */
159  virtual ~Client(){}
160 
161 protected:
162  /**
163  * @brief the derived user's Client has the option to stop the current batch of event
164  * dispatching.
165  * @details for example, if the user's Client decides it has handled all interested
166  * messages and wants to skip the remaining messages within the CURRENT batch, call
167  * this within any callback functions.
168  * use with caution, only when it is absolutely certain that there is NO messages of
169  * ANY type the Client need to care are within the current batch.
170  */
171  void batchDone() {
172  batchDone_ = true;
173  }
174 
175 public:
176  /**
177  * @brief the following are for internal use, don't change or override
178  */
179  void stopped(std::exception const&e) noexcept {
180  try {
181  stoppedCb(e);
182  } catch (...) {}
183  }
184 
185  bool dropped() noexcept {
186  bool res = true;
187  try {
188  res = droppedCb();
189  } catch (...) {}
190  return res;
191  }
192 
193  template <typename Iterator>
194  void handleRangeImpl(Iterator it,
195  Iterator end, uint16_t threadId) {
196  CcClient& c = static_cast<CcClient&>(*this);
197  for (;hmbdc_likely(!batchDone_ && it != end); ++it) {
198  MessageDispacher<CcClient, Interests>()(
199  c, *static_cast<MessageHead*>(*it));
200  }
201  batchDone_ = false;
202  }
203 
204 protected:
205  bool batchDone_ = false; ///not part of API, do not touch
206 };
207 
208 }} //hmbdc::app
char const * hmbdcName() const
return the name of thread that runs this client, override if necessary
Definition: Client.hpp:75
virtual ~Client()
trivial
Definition: Client.hpp:159
std::tuple< char const *, int > schedSpec() const
an overrideable method. returns the schedule policy and priority, override if necessary priority is o...
Definition: Client.hpp:85
template that convert a regular message to be a reply used in request / reply sync messaging - see Re...
Definition: Message.hpp:363
virtual bool droppedCb()
callback called after the Client is safely taken out of the Context
Definition: Client.hpp:135
virtual void invokedCb(uint16_t threadSerialNumber)
this callback is called all the time (frequently) - the exact timing is after a batch of messages are...
Definition: Client.hpp:152
a std tuple holding REPLY messages types it can dispatch
void batchDone()
the derived user&#39;s Client has the option to stop the current batch of event dispatching.
Definition: Client.hpp:171
void stopped(std::exception const &e) noexcept
the following are for internal use, don&#39;t change or override
Definition: Client.hpp:179
Definition: MetaUtils.hpp:205
size_t maxBatchMessageCount() const
an overridable method. client receives events in batches and the max batch size is controllable when ...
Definition: Client.hpp:97
virtual void stoppedCb(std::exception const &e)
callback called when this Client is taken out of message dispatching
Definition: Client.hpp:123
virtual void messageDispatchingStartedCb(uint16_t threadSerialNumber)
called before any messages got dispatched - only once
Definition: Client.hpp:109
a trait class, if a Client can only run on a single specific thread in Pool, derive the Client from i...
Definition: Client.hpp:19
Definition: MetaUtils.hpp:187
A Client represents a thread of execution/a task. The execution is managed by a Context. a Client object could participate in message dispatching as the receiver of specifed message types.
Definition: Client.hpp:57
a std tuple holding messages types it can dispatch except REPLYs
Definition: BlockingContext.hpp:183
Definition: Base.hpp:13
a std tuple holding REQUEST messages types it can dispatch
template that convert a regular message to be a request used in request / reply sync messaging - see ...
Definition: Message.hpp:339