hmbdc
simplify-high-performance-messaging-programming
Message.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/time/Time.hpp"
5 #include <stdint.h>
6 #include <utility>
7 #include <ostream>
8 #include <type_traits>
9 #include <memory.h>
10 
11 namespace hmbdc { namespace app {
12 
13 
14 /**
15 * see @example hmbdc.cpp
16 * @example perf-tcpcast.cpp
17 */
18 
19 /**
20  * @class hasTag<>
21  * @brief each message type has 16 bit tag
22  * @details If a Messaeg type has a dtor or containing a data member that has it, the dtor(s)
23  * are NOT going to be called by hmbdc framework after the message is injected into a Context.
24  * User code has to handle it.
25  * Otherwise, it is very simple to define a message:
26  * @snippet hmbdc.cpp define a message
27  * @tparam tag 16 bit unsigned tag
28  */
29 template <uint16_t tag>
30 struct hasTag {
31  enum {typeTag = tag};
32 };
33 
34 struct MessageHead {
35  MessageHead(uint16_t typeTag)
36  : reserved2(0)
37  , reserved(0)
38  , typeTag(typeTag)
39  {}
40  template <typename Message> Message& get();
41  template <typename Message> Message const& get() const;
42  template <typename Message> void setPayload(Message const&);
43  template <typename Message, typename ...Args> void setPayloadInPlace(Args&& ... args);
44  uint32_t reserved2;
45  uint16_t reserved;
46  uint16_t typeTag;
47 
48  friend
49  std::ostream& operator << (std::ostream& os, MessageHead const & h) {
50  return os << h.reserved << ' ' << h.typeTag;
51  }
52 } __attribute__((packed));
53 
54 template <typename Message>
56  template <typename ...Args>
57  MessageWrap(Args&& ... args)
58  : MessageHead(Message::typeTag)
59  , payload(std::forward<Args>(args)...) {
60  static_assert(std::is_class<Message>::value, "wrong type to wrap");
61  }
62  Message payload;
63 
64  friend
65  std::ostream& operator << (std::ostream& os, MessageWrap<Message> const & w) {
66  return os << static_cast<MessageHead const&>(w) << ' ' << w.payload;
67  }
68 };
69 
70 template <typename Message>
71 Message&
72 MessageHead::get() {
73  return static_cast<MessageWrap<Message>*>(this)->payload;
74 }
75 
76 template <typename Message>
77 Message const&
78 MessageHead::get() const{
79  return static_cast<MessageWrap<Message> const*>(this)->payload;
80 }
81 
82 template <typename Message>
83 void
84 MessageHead::
85 setPayload(Message const& m) {
86  new (&get<Message>()) Message(m);
87  typeTag = Message::typeTag;
88 }
89 
90 template <typename Message, typename ...Args>
91 void
92 MessageHead::
93 setPayloadInPlace(Args&& ... args) {
94  new (&get<Message>()) Message(std::forward<Args>(args)...);
95  typeTag = Message::typeTag;
96 }
97 
98 struct Flush
99 : hasTag<0> {
100 };
101 
102 template <size_t MaxStreamableSize>
103 struct LoggingT
104 : hasTag<3> {
105  char payload[MaxStreamableSize];
106 } __attribute__((__may_alias__, packed));
107 
108 /**
109  * @class JustBytes
110  * @brief A special type of message
111  * @details When a Client declare this type as interested, all
112  * messages regardless of their type will be delievered in byte form to this client
113  * in additon to regular messages - see Client.hpp and ConsoleClient.hpp documentation
114  */
115 struct JustBytes
116 : hasTag<4> {
117  JustBytes() = delete;
118 };
119 
120 struct Trace {
121  Trace()
122  : tsIndex(1) {
123  ts[0] = (time::SysTime::now());
124  }
125  uint8_t tsIndex;
126  time::SysTime ts[6];
127  friend
128  std::ostream& operator << (std::ostream& os, Trace const & t) {
129  for (auto i = 0u; i < t.tsIndex; ++i) os << t.ts[i] << ' ';
130  return os;
131  }
132 };
133 
134 template<>
136  MessageWrap(uint16_t tag, void const* bytes, size_t len)
137  : MessageHead(tag) {
138  memcpy(&payload, bytes, len);
139  }
140  uint8_t payload;
141 
142  friend
143  std::ostream& operator << (std::ostream& os, MessageWrap<JustBytes> const & w) {
144  return os << static_cast<MessageHead const&>(w) << " *";
145  }
146 };
147 static_assert(sizeof(MessageWrap<JustBytes>) == sizeof(MessageHead) + 1, "wrong packing");
148 static_assert(sizeof(MessageWrap<Flush>) == sizeof(MessageHead) + sizeof(Flush), "wrong packing");
149 
150 /**
151  * @class hasMemoryAttachment
152  * @brief if a specific hmbdc network transport (for example tcpcast) supports message with memory attachment,
153  * the message needs to be derived from this base - as the FIRST base, so it can be handled properly by the
154  * hmbdc network transport when sending and receiving it
155  * @details user on the sending side cannot directly free the attachment, instead the user can provide
156  * a callback func and hmbdc will call it - by default, the callback behavior is to call free on attachment
157  */
159  using AfterConsumedCleanupFunc = void (*)(hasMemoryAttachment*);
160 
161  /**
162  * @brief default ctor
163  * @details allocate and release thru heap
164  */
166  : afterConsumedCleanupFunc(hasMemoryAttachment::free)
167  , attachment(NULL)
168  , len(0) {
169  }
170  enum {
171  flag = 1
172  };
173 
174  /**
175  * @brief file mapped memory
176  * @param fileName file name to map
177  */
178  hasMemoryAttachment(char const* fileName) {
179  map(fileName);
180  }
181 
182  /**
183  * @brief map this object's attached memory to a file
184  * @details the afterConsumedCleanupFunc is automatically set to do the unmap
185  *
186  * @param fileName file to map into memory
187  * @return size of the file mapped
188  */
189  size_t map(char const* fileName);
190  AfterConsumedCleanupFunc afterConsumedCleanupFunc; /// pointing to a func that handles cleaning up the attachment
191  /// it is automatically set, but user can change it as desire
192  /// when the sending side is done with this message,
193  /// this is called by hmbdc automatically.
194  /// however, this is not called on the recv side since
195  /// only the user code knows when to call it
196 
197  /**
198  * @brief does the reverse of map
199  */
200  void
201  unmap() {
202  unmap(this);
203  }
204  void* attachment;
205  size_t len;
206 
207  static
208  void
209  unmap(hasMemoryAttachment*);
210 
211  static
212  void
213  free(hasMemoryAttachment* a) {
214  ::free(a->attachment);
215  a->attachment = nullptr;
216  }
217 
218  friend
219  std::ostream& operator << (std::ostream& os, hasMemoryAttachment const & m) {
220  return os << "hasMemoryAttachment " << m.attachment << ' ' << m.len;
221  }
222 } __attribute__((aligned (8)));
223 
225 : hasTag<5> {
226  uint16_t underlyingMessageTypeTag;
228  size_t segCount;
229 
230  friend
231  std::ostream& operator << (std::ostream& os, StartMemorySegTrain const & m) {
232  return os << "StartAttachmentTrain " << m.underlyingMessageTypeTag
233  << ' ' << m.att << ' ' << m.segCount;
234  }
235 } __attribute__((aligned(8)));
236 
237 struct MemorySeg
238 : hasTag<6> {
239  void const * seg;
240  uint16_t len;
241  friend
242  std::ostream& operator << (std::ostream& os, MemorySeg const & m) {
243  return os << "MemorySeg " << m.seg << ' ' << m.len;
244  }
245 } __attribute__((packed));
246 
247 /**
248  * @class LastSystemMessage
249  * @brief hmbdc system messages use tag values less than this one
250  */
252 : hasTag<999> {
253 };
254 }} //hmbdc::app
Definition: Message.hpp:135
hasMemoryAttachment(char const *fileName)
file mapped memory
Definition: Message.hpp:178
each message type has 16 bit tag
Definition: Message.hpp:30
hasMemoryAttachment()
default ctor
Definition: Message.hpp:165
Definition: Message.hpp:103
Definition: Message.hpp:98
Definition: Message.hpp:34
A special type of message.
Definition: Message.hpp:115
Definition: Message.hpp:224
Definition: Time.hpp:13
hmbdc system messages use tag values less than this one
Definition: Message.hpp:251
Definition: Message.hpp:120
void unmap()
does the reverse of map
Definition: Message.hpp:201
Definition: Message.hpp:55
Definition: Message.hpp:237
if a specific hmbdc network transport (for example tcpcast) supports message with memory attachment...
Definition: Message.hpp:158
Definition: Base.hpp:12