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