1 /*
2 SObjectizer 5.
3 */
4
5 /*!
6 \file
7 \brief Mbox definition.
8 */
9
10 #pragma once
11
12 #include <string>
13 #include <memory>
14 #include <typeindex>
15 #include <utility>
16
17 #include <so_5/declspec.hpp>
18 #include <so_5/compiler_features.hpp>
19
20 #include <so_5/exception.hpp>
21
22 #include <so_5/wait_indication.hpp>
23
24 #include <so_5/mbox_fwd.hpp>
25 #include <so_5/message.hpp>
26 #include <so_5/mhood.hpp>
27
28 namespace so_5
29 {
30
31 /*!
32 * \since
33 * v.5.5.9
34 *
35 * \brief Result of checking delivery posibility.
36 */
37 enum class delivery_possibility_t
38 {
39 must_be_delivered,
40 no_subscription,
41 disabled_by_delivery_filter,
42 /*!
43 * The actual message is hidden by an envelope.
44 *
45 * \since
46 * v.5.5.23
47 */
48 hidden_by_envelope
49 };
50
51 //
52 // delivery_filter_t
53 //
54 /*!
55 * \since
56 * v.5.5.5
57 *
58 * \brief An interface of delivery filter object.
59 */
60 class SO_5_TYPE delivery_filter_t
61 {
62 // Note: clang-3.9 requires this on Windows platform.
63 delivery_filter_t( const delivery_filter_t & ) = delete;
64 delivery_filter_t( delivery_filter_t && ) = delete;
65 delivery_filter_t & operator=( const delivery_filter_t & ) = delete;
66 delivery_filter_t & operator=( delivery_filter_t && ) = delete;
67 public :
68 delivery_filter_t() = default;
69 virtual ~delivery_filter_t() noexcept = default;
70
71 //! Checker for a message instance.
72 /*!
73 * \retval true message must be delivered to a receiver.
74 * \retval false message must be descarded.
75 */
76 virtual bool
77 check(
78 //! Receiver of the message.
79 const agent_t & receiver,
80 //! Message itself.
81 message_t & msg ) const noexcept = 0;
82 };
83
84 //
85 // delivery_filter_unique_ptr_t
86 //
87 /*!
88 * \since
89 * v.5.5.5
90 *
91 * \brief An alias of unique_ptr for delivery_filter.
92 */
93 using delivery_filter_unique_ptr_t =
94 std::unique_ptr< delivery_filter_t >;
95
96 //
97 // mbox_type_t
98 //
99 /*!
100 * \since
101 * v.5.5.3
102 *
103 * \brief Type of the message box.
104 *
105 * \note
106 * This type is no more marked as deprecated.
107 */
108 enum class mbox_type_t
109 {
110 //! Mbox is Multi-Producer and Multi-Consumer.
111 //! Anyone can send messages to it, there can be many subscribers.
112 multi_producer_multi_consumer,
113 //! Mbox is Multi-Producer and Single-Consumer.
114 //! Anyone can send messages to it, there can be only one subscriber.
115 multi_producer_single_consumer
116 };
117
118 //
119 // abstract_message_box_t
120 //
121
122 //! Mail box class.
123 /*!
124 * The class serves as an interface for sending and receiving messages.
125 *
126 * All mboxes can be created via the SObjectizer Environment. References to
127 * mboxes are stored and manipulated by so_5::mbox_t objects.
128 *
129 * \see environment_t::schedule_timer(), environment_t::single_timer().
130 */
131 class SO_5_TYPE abstract_message_box_t : protected atomic_refcounted_t
132 {
133 friend class intrusive_ptr_t< abstract_message_box_t >;
134
135 /*!
136 * It is necessary for for access to do_deliver_message_from_timer().
137 *
138 * \note
139 * Added in v.5.5.18.
140 */
141 friend class so_5::impl::mbox_iface_for_timers_t;
142
143 abstract_message_box_t( const abstract_message_box_t & ) = delete;
144 abstract_message_box_t( abstract_message_box_t && ) = delete;
145 abstract_message_box_t &
146 operator=( const abstract_message_box_t & ) = delete;
147 abstract_message_box_t &
148 operator=( abstract_message_box_t && ) = delete;
149
150 public:
151 abstract_message_box_t() = default;
152 virtual ~abstract_message_box_t() noexcept = default;
153
154 /*!
155 * \since
156 * v.5.4.0
157 *
158 * \brief Unique ID of this mbox.
159 */
160 virtual mbox_id_t
161 id() const = 0;
162
163 //! Add the message handler.
164 virtual void
165 subscribe_event_handler(
166 //! Message type.
167 const std::type_index & type_index,
168 //! Optional message limit for that message type.
169 const message_limit::control_block_t * limit,
170 //! Agent-subscriber.
171 agent_t & subscriber ) = 0;
172
173 //! Remove all message handlers.
174 virtual void
175 unsubscribe_event_handlers(
176 //! Message type.
177 const std::type_index & type_index,
178 //! Agent-subscriber.
179 agent_t & subscriber ) = 0;
180
181 //! Get the mbox name.
182 virtual std::string
183 query_name() const = 0;
184
185 /*!
186 * \since
187 * v.5.5.3
188 *
189 * \brief Get the type of message box.
190 *
191 * \note This method is primarily intended for internal usage.
192 * It is useful sometimes in subscription-related operations
193 * because there is no need to do some actions for MPSC mboxes.
194 */
195 virtual mbox_type_t
196 type() const = 0;
197
198 /*!
199 * \name Comparision.
200 * \{
201 */
operator ==(const abstract_message_box_t & o) const202 bool operator==( const abstract_message_box_t & o ) const noexcept
203 {
204 return id() == o.id();
205 }
206
operator <(const abstract_message_box_t & o) const207 bool operator<( const abstract_message_box_t & o ) const noexcept
208 {
209 return id() < o.id();
210 }
211 /*!
212 * \}
213 */
214
215 /*!
216 * \since
217 * v.5.5.4
218 *
219 * \brief Deliver message for all subscribers with respect to message
220 * limits.
221 *
222 * \note
223 * Since v.5.6.0 this method is used for deliverance of ordinary
224 * messages/signals and for deliverance of enveloped messages.
225 */
226 virtual void
227 do_deliver_message(
228 //! Type of the message to deliver.
229 const std::type_index & msg_type,
230 //! A message instance to be delivered.
231 const message_ref_t & message,
232 //! Current deep of overlimit reaction recursion.
233 unsigned int overlimit_reaction_deep ) = 0;
234
235 /*!
236 * \name Methods for working with delivery filters.
237 * \{
238 */
239 /*!
240 * \since
241 * v.5.5.5
242 *
243 * \brief Set a delivery filter for message type and subscriber.
244 *
245 * \note If there already is a delivery filter for that
246 * (msg_type,subscriber) pair then old delivery filter will
247 * be replaced by new one.
248 */
249 virtual void
250 set_delivery_filter(
251 //! Message type to be filtered.
252 const std::type_index & msg_type,
253 //! Filter to be set.
254 //! A caller must guaranted the validity of this reference.
255 const delivery_filter_t & filter,
256 //! A subscriber for the message.
257 agent_t & subscriber ) = 0;
258
259 /*!
260 * \since
261 * v.5.5.5
262 *
263 * \brief Removes delivery filter for message type and subscriber.
264 */
265 virtual void
266 drop_delivery_filter(
267 const std::type_index & msg_type,
268 agent_t & subscriber ) noexcept = 0;
269 /*!
270 * \}
271 */
272
273 //! SObjectizer Environment for which the mbox is created.
274 /*!
275 * \since
276 * v.5.6.0
277 */
278 virtual so_5::environment_t &
279 environment() const noexcept = 0;
280
281 protected :
282 /*!
283 * \since
284 * v.5.5.18
285 *
286 * \brief Special method for message delivery from a timer thread.
287 *
288 * A message delivery from timer thread is somewhat different from
289 * an ordinary message delivery. Especially in the case when
290 * target mbox is a message chain. If that message chain is
291 * full and some kind of overflow reaction is specified (like waiting
292 * for some time or throwing an exception) then it can lead to
293 * undesired behaviour of the whole application. To take care about
294 * these cases a new method is introduced.
295 *
296 * Note that implementation of that method in abstract_message_box_t
297 * class is just a proxy for do_deliver_message() method. It is done
298 * to keep compatibility with previous versions of SObjectizer.
299 * The actual implementation of that method is present only in
300 * message chains.
301 */
302 virtual void
303 do_deliver_message_from_timer(
304 //! Type of the message to deliver.
305 const std::type_index & msg_type,
306 //! A message instance to be delivered.
307 const message_ref_t & message );
308
309 /*!
310 * \brief Helper for calling do_deliver_message_from_timer in
311 * derived classes.
312 *
313 * Sometimes an user want to implement its own mbox on top
314 * of an existing mbox. Something like that:
315 * \code
316 * class my_custom_mbox : public so_5::abstract_message_box_t
317 * {
318 * // Actual mbox to perform all work.
319 * const so_5::mbox_t actual_mbox_;
320 * ...
321 * void do_deliver_message_from_timer(
322 * const std::type_index & msg_type,
323 * const so_5::message_ref_t & message )
324 * {
325 * ... // Do some specific stuff.
326 * // Work should be delegated to actual_mbox_ but we
327 * // can't simply call actual_mbox_->do_deliver_message_from_timer()
328 * // because it is a protected method.
329 * // But we can call delegate_deliver_message_from_timer():
330 * delegate_deliver_message_from_timer(
331 * actual_mbox_, msg_type, message );
332 * }
333 * };
334 * \endcode
335 *
336 * \since
337 * v.5.5.23
338 */
339 static void
delegate_deliver_message_from_timer(abstract_message_box_t & mbox,const std::type_index & msg_type,const message_ref_t & message)340 delegate_deliver_message_from_timer(
341 //! Mbox to be used for message delivery.
342 abstract_message_box_t & mbox,
343 //! Type of the message to deliver.
344 const std::type_index & msg_type,
345 //! A message instance to be delivered.
346 const message_ref_t & message )
347 {
348 mbox.do_deliver_message_from_timer( msg_type, message );
349 }
350 };
351
352 namespace low_level_api {
353
354 //! Deliver message.
355 /*!
356 * Mbox takes care about destroying a message object.
357 *
358 * \attention
359 * This function ensures that Message is a classical message
360 * with an actual data (e.g. \a msg shouldn't be nullptr).
361 *
362 * \note
363 * This function is a part of low-level SObjectizer's interface.
364 * Because of that this function can be removed or changed in some
365 * future version without prior notice.
366 *
367 * \since
368 * v.5.6.0
369 */
370 template< class Message >
371 void
deliver_message(abstract_message_box_t & target,std::type_index subscription_type,std::unique_ptr<Message> msg)372 deliver_message(
373 //! Destination for message.
374 abstract_message_box_t & target,
375 //! Subscription type for that message.
376 std::type_index subscription_type,
377 //! Message data.
378 std::unique_ptr< Message > msg )
379 {
380 ensure_classical_message< Message >();
381 ensure_message_with_actual_data( msg.get() );
382
383 target.do_deliver_message(
384 std::move(subscription_type),
385 message_ref_t{ msg.release() },
386 1u );
387 }
388
389 //! Deliver message.
390 /*!
391 * This function is necessary for cases when message object
392 * is already present as message_ref_t.
393 *
394 * \note
395 * This function is a part of low-level SObjectizer's interface.
396 * Because of that this function can be removed or changed in some
397 * future version without prior notice.
398 *
399 * \since
400 * v.5.6.0
401 */
402 inline void
deliver_message(abstract_message_box_t & target,std::type_index subscription_type,message_ref_t msg)403 deliver_message(
404 //! Destination for message.
405 abstract_message_box_t & target,
406 //! Subscription type for that message.
407 std::type_index subscription_type,
408 //! Message data.
409 message_ref_t msg )
410 {
411 target.do_deliver_message(
412 std::move(subscription_type),
413 std::move(msg),
414 1u );
415 }
416
417 //! Deliver signal.
418 /*!
419 * \attention
420 * This function ensures that Message is a type of a signal.
421 *
422 * \note
423 * This function is a part of low-level SObjectizer's interface.
424 * Because of that this function can be removed or changed in some
425 * future version without prior notice.
426 *
427 * \since
428 * v.5.6.0
429 */
430 template< class Message >
431 void
deliver_signal(abstract_message_box_t & target)432 deliver_signal(
433 //! Destination for signal.
434 abstract_message_box_t & target )
435 {
436 ensure_signal< Message >();
437
438 target.do_deliver_message(
439 message_payload_type< Message >::subscription_type_index(),
440 message_ref_t(),
441 1u );
442 }
443
444 } /* namespace low_level_api */
445
446 } /* namespace so_5 */
447
448