1 /*
2 SObjectizer 5.
3 */
4
5 /*!
6 \file
7 \brief A base class for the agent messages definition.
8 */
9
10 #pragma once
11
12 #include <so_5/declspec.hpp>
13 #include <so_5/exception.hpp>
14 #include <so_5/atomic_refcounted.hpp>
15 #include <so_5/types.hpp>
16
17 #include <so_5/agent_ref_fwd.hpp>
18
19 #include <type_traits>
20 #include <typeindex>
21 #include <functional>
22 #include <future>
23 #include <atomic>
24
25 namespace so_5
26 {
27
28 //
29 // message_t
30 //
31
32 //! A base class for agent messages.
33 /*!
34 * All messages for agents must be derived from this class.
35 *
36 * \attention This class should be used for all messages which
37 * have an actual message data. For signals (messages without any data)
38 * a signal_t class should be used as a base class.
39 *
40 * \note
41 * Class message_t is derived from atomic_refcounted_t.
42 * But atomic_refcounted_t is not Copyable or Movable class.
43 * It means that copy/move constructors and operators for message_t
44 * have no influence on the reference counter inside message_t.
45 */
46 class SO_5_TYPE message_t : public atomic_refcounted_t
47 {
48 friend class impl::internal_message_iface_t;
49 public:
50 //! A short typedef for kind of message.
51 /*!
52 * \since
53 * v.5.5.23
54 */
55 using kind_t = ::so_5::message_kind_t;
56
57 message_t();
58 message_t( const message_t & other );
59 message_t( message_t && other );
60
61 message_t &
62 operator=( const message_t & other );
63 message_t &
64 operator=( message_t && other );
65
66 virtual ~message_t() noexcept = default;
67
68 /*!
69 * \brief Helper method for safe get of message mutability flag.
70 *
71 * Use this method instead of direct call to so5_message_mutability()
72 * because \a what will be nullptr for signals.
73 */
74 friend message_mutability_t
message_mutability(const intrusive_ptr_t<message_t> & what)75 message_mutability( const intrusive_ptr_t<message_t> & what ) noexcept
76 {
77 message_mutability_t r = message_mutability_t::immutable_message;
78 if( what )
79 r = what->so5_message_mutability();
80 return r;
81 }
82
83 /*!
84 * \brief Helper method for get message mutability flag.
85 */
86 friend message_mutability_t
message_mutability(const message_t & what)87 message_mutability( const message_t & what ) noexcept
88 {
89 return what.so5_message_mutability();
90 }
91
92 /*!
93 * \brief Helper method for safe change message mutability flag.
94 *
95 * Use this method instead of direct call to so5_change_mutability()
96 * because \a what will be nullptr for signals.
97 *
98 * \note
99 * This is a very dangerous operation. Don't do it by yourselt.
100 * See message_t::so5_change_mutability() for more details.
101 *
102 * \attention
103 * This function can throw.
104 * For example underlying message object can prohibit changing
105 * of message mutability.
106 */
107 friend void
change_message_mutability(intrusive_ptr_t<message_t> & what,message_mutability_t mutability)108 change_message_mutability(
109 //! Message instance to be modified if it is not a signal.
110 intrusive_ptr_t< message_t> & what,
111 //! New mutability flag for the message.
112 message_mutability_t mutability )
113 {
114 if( what )
115 what->so5_change_mutability( mutability );
116 }
117
118 /*!
119 * \brief Helper method for change message mutability flag.
120 *
121 * \note
122 * This is a very dangerous operation. Don't do it by yourselt.
123 * See message_t::so5_change_mutability() for more details.
124 *
125 * \attention
126 * This function can throw.
127 * For example underlying message object can prohibit changing
128 * of message mutability.
129 */
130 friend void
change_message_mutability(message_t & what,message_mutability_t mutability)131 change_message_mutability(
132 //! Message instance to be modified.
133 message_t & what,
134 //! New mutability flag for the message.
135 message_mutability_t mutability )
136 {
137 what.so5_change_mutability( mutability );
138 }
139
140 /*!
141 * \brief Helper method for quering kind of the message.
142 *
143 * This helper function is necessary because it correctly
144 * handles case when message is a signal. In that case pointer
145 * to message instance will be null.
146 *
147 * \note
148 * This function is part of internal implementation of SObjectizer.
149 * Don't use it directly. It can be a subject of changes in some
150 * future versions.
151 *
152 * \since
153 * v.5.5.23
154 */
155 friend message_kind_t
message_kind(const so_5::intrusive_ptr_t<message_t> & what)156 message_kind(
157 const so_5::intrusive_ptr_t< message_t > & what )
158 {
159 if( what )
160 return what->so5_message_kind();
161 else
162 return message_kind_t::signal;
163 }
164
165 /*!
166 * \brief Helper method for quering kind of the message.
167 *
168 * \note
169 * This function is part of internal implementation of SObjectizer.
170 * Don't use it directly. It can be a subject of changes in some
171 * future versions.
172 *
173 * \since
174 * v.5.5.23
175 */
176 friend message_kind_t
message_kind(const message_t & what)177 message_kind(
178 const message_t & what )
179 {
180 return what.so5_message_kind();
181 }
182
183 private :
184 /*!
185 * \brief Is message mutable or immutable?
186 *
187 * By default the message is immutable.
188 * \since
189 * v.5.5.19
190 */
191 message_mutability_t m_mutability;
192
193 /*!
194 * \brief Get message mutability flag.
195 *
196 * \note
197 * This method is intended to be used by SObjectizer and
198 * low-level SObjectizer extension. Because of that it is not
199 * guaranteed that this method is part of stable SObjectizer API.
200 * It can be changed or even removed in any future versions
201 * of SObjectizer.
202 *
203 * \note
204 * This is a virual method because its behavious must be changed in
205 * msg_service_request_t.
206 *
207 * \since
208 * v.5.5.19
209 */
210 virtual message_mutability_t
so5_message_mutability() const211 so5_message_mutability() const noexcept { return m_mutability; }
212
213 /*!
214 * \brief Change message mutabilty flag.
215 *
216 * \attention
217 * Changing mutability from message_mutability_t::immutable_message
218 * to message_mutability_t::mutable_message is a very bad idea.
219 * Please don't do this until you are know what you are doing.
220 *
221 * \note
222 * This method is intended to be used by SObjectizer and
223 * low-level SObjectizer extension. Because of that it is not
224 * guaranteed that this method is part of stable SObjectizer API.
225 * It can be changed or even removed in any future versions
226 * of SObjectizer.
227 *
228 * \note
229 * This is a virual method because its behavious must be changed in
230 * msg_service_request_t.
231 *
232 * \attention
233 * This function can throw.
234 * For example a derived class can prohibit changing
235 * of message mutability.
236 *
237 * \since
238 * v.5.5.19
239 */
240 virtual void
so5_change_mutability(message_mutability_t mutability)241 so5_change_mutability(
242 //! New mutability flag for
243 message_mutability_t mutability )
244 {
245 m_mutability = mutability;
246 }
247
248 /*!
249 * \brief Detect the kind of the message.
250 *
251 * \note
252 * This method is intended to be used by SObjectizer and
253 * low-level SObjectizer extension. Because of that it is not
254 * guaranteed that this method is part of stable SObjectizer API.
255 * It can be changed or even removed in any future versions
256 * of SObjectizer.
257 *
258 * \since
259 * v.5.5.23
260 */
261 virtual kind_t
so5_message_kind() const262 so5_message_kind() const noexcept
263 {
264 return kind_t::classical_message;
265 }
266 };
267
268 //
269 // message_ref_t
270 //
271 //! A smart reference to the message.
272 /*!
273 * \note Defined as typedef since v.5.2.0
274 */
275 using message_ref_t = intrusive_ptr_t< message_t >;
276
277 //
278 // signal_t
279 //
280 //! A base class for agent signals.
281 /*!
282 * \since
283 * v.5.2.0
284 *
285 * All signals (messages without any data) for agents should be
286 * derived from this class.
287 */
288 class SO_5_TYPE signal_t
289 : public message_t
290 {
291 private :
292 // Note: clang-3.9 requires this on Windows platform.
293 signal_t( const signal_t & ) = delete;
294 signal_t( signal_t && ) = delete;
295 signal_t & operator=( const signal_t & ) = delete;
296 signal_t & operator=( signal_t && ) = delete;
297
298 /*!
299 * Private constructor to disable creation of instances of
300 * derived classes.
301 */
302 signal_t() = default;
303
304 // Note: this method has no sence in v.5.5, becasue instances
305 // of that class are not created at all.
306 // But that can be changed in v.5.6.0.
307 kind_t
so5_message_kind() const308 so5_message_kind() const noexcept override
309 {
310 return kind_t::classical_message;
311 }
312
313 public :
314 ~signal_t() noexcept override = default;
315 };
316
317 //
318 // user_type_message_t
319 //
320 /*!
321 * \brief Template class for representing object of user type as a message.
322 *
323 * \tparam T type of actual message. This type must have move- or copy
324 * constructor.
325 *
326 * \since
327 * v.5.5.9
328 */
329 template< typename T >
330 struct user_type_message_t : public message_t
331 {
332 //! Instance of user message.
333 /*!
334 * \note
335 * Since v.5.5.19 it is not a const object anymore.
336 */
337 T m_payload;
338
339 //! Initializing constructor.
340 template< typename... Args >
user_type_message_tso_5::user_type_message_t341 user_type_message_t( Args &&... args )
342 : m_payload{ std::forward< Args >( args )... }
343 {}
344
345 //! Initialization from const T object.
user_type_message_tso_5::user_type_message_t346 user_type_message_t( const T & o )
347 : m_payload{ o }
348 {}
349
350 //! Initialization from non-const T object.
user_type_message_tso_5::user_type_message_t351 user_type_message_t( T & o )
352 : m_payload{ o }
353 {}
354
355 //! Initialization from temporary T object.
user_type_message_tso_5::user_type_message_t356 user_type_message_t( T && o )
357 : m_payload{ std::move(o) }
358 {}
359
360 private :
361 kind_t
so5_message_kindso_5::user_type_message_t362 so5_message_kind() const noexcept override
363 {
364 return kind_t::user_type_message;
365 }
366 };
367
368 //
369 // immutable_msg
370 //
371 /*!
372 * \brief A special marker for immutable message.
373 *
374 * This marker tells that message can be sent to several receivers and
375 * nobody can change the message content.
376 *
377 * \tparam M type of the message.
378 *
379 * \since
380 * v.5.5.19
381 */
382 template< typename M >
383 struct immutable_msg final {};
384
385 //
386 // mutable_msg
387 //
388 /*!
389 * \brief A special marker for mutable message.
390 *
391 * This marker tells that message can be sent only for one receiver.
392 * And that receiver will get an exclusive access to the message content.
393 * It means that receiver can change message's content.
394 *
395 * \tparam M type of the message.
396 *
397 * \since
398 * v.5.5.19
399 */
400 template< typename M >
401 struct mutable_msg final {};
402
403 namespace details {
404
405 //
406 // message_mutability_traits
407 //
408 /*!
409 * \brief Detector of message type traits in dependency of message immutability
410 * or mutability.
411 *
412 * \since
413 * v.5.5.19
414 */
415 template< typename T >
416 struct message_mutability_traits
417 {
418 using payload_type = typename std::decay<T>::type;
419 using subscription_type = payload_type;
420 using mhood_param_type = payload_type;
421
422 static const constexpr message_mutability_t mutability =
423 message_mutability_t::immutable_message;
424 };
425
426 template< typename T >
427 struct message_mutability_traits< immutable_msg<T> >
428 {
429 using payload_type = T;
430 using subscription_type = T;
431 using mhood_param_type = T;
432
433 static const constexpr message_mutability_t mutability =
434 message_mutability_t::immutable_message;
435 };
436
437 template< typename T >
438 struct message_mutability_traits< mutable_msg<T> >
439 {
440 using payload_type = T;
441 using subscription_type = mutable_msg<T>;
442 using mhood_param_type = mutable_msg<T>;
443
444 static const constexpr message_mutability_t mutability =
445 message_mutability_t::mutable_message;
446 };
447
448 } /* namespace details */
449
450 //
451 // is_user_type_message
452 //
453 /*!
454 * \since
455 * v.5.5.9
456 *
457 * \brief A helper for detection presence of message of user type.
458 *
459 * \tparam M type to test.
460 */
461 template< typename M >
462 struct is_user_type_message
463 {
464 enum { value = false };
465 };
466
467 template< typename M >
468 struct is_user_type_message< user_type_message_t< M > >
469 {
470 enum { value = true };
471 };
472
473 //
474 // is_signal
475 //
476 /*!
477 * \since
478 * v.5.5.4
479 *
480 * \brief A helper class for checking that message is a signal.
481 */
482 template< class T >
483 struct is_signal
484 {
485 enum { value = std::is_base_of<
486 signal_t,
487 typename details::message_mutability_traits<T>::payload_type >::value };
488 };
489
490 //
491 // is_classical_message
492 //
493 /*!
494 * \since
495 * v.5.5.9
496 *
497 * \brief A helper class for checking that message is a classical message
498 * derived from %message_t class.
499 */
500 template< class T >
501 struct is_classical_message
502 {
503 enum { value = std::is_base_of<
504 message_t,
505 typename details::message_mutability_traits<T>::payload_type >::value };
506 };
507
508 //
509 // is_mutable_message
510 //
511 /*!
512 * \brief A helper class for checking that message is a mutable message.
513 *
514 * \since
515 * v.5.5.19
516 */
517 template< typename T >
518 struct is_mutable_message
519 {
520 enum { value = false };
521 };
522
523 template< typename T >
524 struct is_mutable_message< mutable_msg<T> >
525 {
526 enum { value = true };
527 };
528
529 //
530 // ensure_not_signal
531 //
532 /*!
533 * \since
534 * v.5.2.0
535 *
536 * \brief A special compile-time checker to guarantee that the message
537 * class is not a signal class.
538 */
539 template< class Msg >
540 void
ensure_not_signal()541 ensure_not_signal()
542 {
543 static_assert( !is_signal< Msg >::value,
544 "message class must be derived from the message_t" );
545 }
546
547 //
548 // ensure_message_with_actual_data
549 //
550 /*!
551 * \since
552 * v.5.2.0
553 *
554 * \brief A special checker to guarantee that the message is an instance
555 * of the message_t (not signal_t) and has a not-null pointer
556 * to the message data.
557 *
558 * \note A check for the inheritance from the message_t is done at compile-time.
559 *
560 * \tparam Msg message type to be checked.
561 */
562 template< class Msg >
563 void
ensure_message_with_actual_data(const Msg * m)564 ensure_message_with_actual_data( const Msg * m )
565 {
566 ensure_not_signal< Msg >();
567
568 if( !m )
569 throw so_5::exception_t(
570 "an attempt to send a message via nullptr",
571 so_5::rc_null_message_data );
572 }
573
574 //
575 // ensure_not_mutable_signal
576 //
577 /*!
578 * \brief A special compile-time checker to guarantee that S is not a
579 * mutable signal.
580 *
581 * This check is intended to prevent usage of mutable_msg<S> where S is
582 * a signal type.
583 *
584 * \since
585 * v.5.5.19
586 */
587 template< class S >
588 void
ensure_not_mutable_signal()589 ensure_not_mutable_signal()
590 {
591 static_assert( !is_signal<S>::value ||
592 message_mutability_t::immutable_message ==
593 details::message_mutability_traits<S>::mutability,
594 "usage of mutable_msg<S> where S is a signal is prohibited" );
595 }
596
597 //
598 // ensure_signal
599 //
600 /*!
601 * \since
602 * v.5.2.0
603 *
604 * \brief A special compile-time checker to guarantee that the Msg is derived
605 * from the signal_t.
606 *
607 * \tparam Msg signal type to be checked.
608 */
609 template< class Msg >
610 void
ensure_signal()611 ensure_signal()
612 {
613 static_assert( is_signal< Msg >::value,
614 "expected a type derived from the signal_t" );
615
616 // Added in v.5.5.19.
617 // Msg must not be a mutable_msg<S>.
618 ensure_not_mutable_signal<Msg>();
619 }
620
621 //
622 // ensure_classical_message
623 //
624 /*!
625 * \since
626 * v.5.5.9
627 *
628 * \brief A special compile-time checker to guarantee that Msg is derived from
629 * %message_t.
630 *
631 * \tparam Msg type to be checked.
632 */
633 template< typename Msg >
634 void
ensure_classical_message()635 ensure_classical_message()
636 {
637 static_assert( is_classical_message< Msg >::value,
638 "expected a type derived from the message_t" );
639 }
640
641 //
642 // message_payload_type_impl
643 //
644 /*!
645 * \since
646 * v.5.5.9
647 *
648 * \brief Implementation details for %message_payload_type.
649 *
650 * \note This specialization is for cases where T is derived from message_t.
651 * In that case payload_type is the same as envelope_type.
652 */
653 template< typename T, bool is_classical_message >
654 struct message_payload_type_impl
655 {
656 //! Mutability traits for this message type.
657 using mutability_traits = details::message_mutability_traits<T>;
658
659 //! Type visible to user.
660 using payload_type = typename mutability_traits::payload_type;
661 //! Type for message delivery.
662 using envelope_type = payload_type;
663 //! Type to which subscription must be done.
664 using subscription_type = typename mutability_traits::subscription_type;
665
666 //! Is it a signal type or message type.
667 static constexpr const bool is_signal = ::so_5::is_signal<T>::value;
668
669 //! Type ID for subscription.
subscription_type_indexso_5::message_payload_type_impl670 inline static std::type_index subscription_type_index()
671 {
672 // T must not be a mutable_msg<T>.
673 ensure_not_mutable_signal<T>();
674
675 return typeid(subscription_type);
676 }
677
678 //! Helper for extraction of pointer to payload part.
679 /*!
680 * \note This method return non-const pointer because it is
681 * necessary for so_5::mhood_t.
682 */
683 inline static payload_type *
extract_payload_ptrso_5::message_payload_type_impl684 extract_payload_ptr( message_ref_t & msg )
685 {
686 return dynamic_cast< payload_type * >( msg.get() );
687 }
688
689 //! Helper for extraction of pointer to envelope part.
690 /*!
691 * The same implementation as for extract_envelope_ptr().
692 */
693 inline static envelope_type *
extract_envelope_ptrso_5::message_payload_type_impl694 extract_envelope_ptr( message_ref_t & msg )
695 {
696 return dynamic_cast< envelope_type * >( msg.get() );
697 }
698
699 //! Helper for getting a const reference to payload part.
700 inline static payload_type &
payload_referenceso_5::message_payload_type_impl701 payload_reference( message_t & msg )
702 {
703 return dynamic_cast< payload_type & >( msg );
704 }
705
706 //! Helper for getting message mutability flag.
707 inline static message_mutability_t
mutabilityso_5::message_payload_type_impl708 mutability()
709 {
710 return mutability_traits::mutability;
711 }
712 };
713
714 /*!
715 * \since
716 * v.5.5.9
717 *
718 * \brief Implementation details for %message_payload_type.
719 *
720 * \note This specialization is for cases where T is not derived from message_t.
721 * In that case payload_type is T, but envelope_type is user_type_message_t<T>.
722 */
723 template< typename T >
724 struct message_payload_type_impl< T, false >
725 {
726 //! Mutability traits for this message type.
727 using mutability_traits = details::message_mutability_traits<T>;
728
729 //! Type visible to user.
730 using payload_type = typename mutability_traits::payload_type;
731 //! Type for message delivery.
732 using envelope_type = user_type_message_t< payload_type >;
733 //! Type to which subscription must be done.
734 using subscription_type = typename mutability_traits::subscription_type;
735
736 //! Is it a signal type or message type.
737 /*!
738 * \note
739 * User-defined type can't be a signal.
740 */
741 static constexpr const bool is_signal = false;
742
743 //! Type ID for subscription.
subscription_type_indexso_5::message_payload_type_impl744 inline static std::type_index subscription_type_index()
745 {
746 return typeid(subscription_type);
747 }
748
749 //! Helper for extraction of pointer to payload part.
750 /*!
751 * \note This method return const pointer because payload is
752 * a const object inside user_type_message_t<T> instance.
753 */
754 inline static payload_type *
extract_payload_ptrso_5::message_payload_type_impl755 extract_payload_ptr( message_ref_t & msg )
756 {
757 auto envelope = dynamic_cast< envelope_type * >( msg.get() );
758 if( !envelope )
759 SO_5_THROW_EXCEPTION( so_5::rc_unexpected_error,
760 "nullptr for user_type_message_t<T> instance" );
761
762 return &(envelope->m_payload);
763 }
764
765 //! Helper for extraction of pointer to envelope part.
766 inline static envelope_type *
extract_envelope_ptrso_5::message_payload_type_impl767 extract_envelope_ptr( message_ref_t & msg )
768 {
769 return dynamic_cast< envelope_type * >( msg.get() );
770 }
771
772 //! Helper for getting a const reference to payload part.
773 inline static payload_type &
payload_referenceso_5::message_payload_type_impl774 payload_reference( message_t & msg )
775 {
776 auto & envelope = dynamic_cast< envelope_type & >( msg );
777 return envelope.m_payload;
778 }
779
780 //! Helper for getting message mutability flag.
781 inline static message_mutability_t
mutabilityso_5::message_payload_type_impl782 mutability()
783 {
784 return mutability_traits::mutability;
785 }
786 };
787
788 //
789 // message_payload_type
790 //
791 /*!
792 * \since
793 * v.5.5.9
794 *
795 * \brief A helper class for detection of payload type of message.
796 *
797 * \tparam T type to test.
798 */
799 template< typename T >
800 struct message_payload_type
801 : public message_payload_type_impl< T,
802 is_classical_message<
803 typename ::so_5::details::message_mutability_traits<T>::payload_type >::value >
804 {
805 };
806
807 template< typename T >
808 struct message_payload_type< user_type_message_t< T > >
809 : public message_payload_type_impl< T, false >
810 {
811 };
812
813 namespace details
814 {
815
816 template< typename Msg >
817 typename std::enable_if<
818 message_mutability_t::mutable_message ==
819 ::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_t & msg)820 mark_as_mutable_if_necessary( message_t & msg )
821 {
822 change_message_mutability( msg, message_mutability_t::mutable_message );
823 }
824
825 /*!
826 * \since
827 * v.5.6.0
828 */
829 template< typename Msg >
830 typename std::enable_if<
831 message_mutability_t::mutable_message ==
832 ::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_ref_t & msg)833 mark_as_mutable_if_necessary( message_ref_t & msg )
834 {
835 change_message_mutability( *msg, message_mutability_t::mutable_message );
836 }
837
838 template< typename Msg >
839 typename std::enable_if<
840 message_mutability_t::mutable_message !=
841 ::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_t &)842 mark_as_mutable_if_necessary( message_t & /*msg*/ )
843 {
844 // Nothing to do.
845 }
846
847 /*!
848 * \since
849 * v.5.6.0
850 */
851 template< typename Msg >
852 typename std::enable_if<
853 message_mutability_t::mutable_message !=
854 ::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_ref_t &)855 mark_as_mutable_if_necessary( message_ref_t & /*msg*/ )
856 {
857 // Nothing to do.
858 }
859
860 template< bool is_signal, typename Msg >
861 struct make_message_instance_impl
862 {
863 using E = typename message_payload_type< Msg >::envelope_type;
864
865 template< typename... Args >
866 static std::unique_ptr< E >
makeso_5::details::make_message_instance_impl867 make( Args &&... args )
868 {
869 ensure_not_signal< Msg >();
870
871 return std::unique_ptr< E >( new E( std::forward< Args >(args)... ) );
872 }
873 };
874
875 template< typename Msg >
876 struct make_message_instance_impl< true, Msg >
877 {
878 static std::unique_ptr< Msg >
makeso_5::details::make_message_instance_impl879 make()
880 {
881 ensure_signal< Msg >();
882
883 return std::unique_ptr< Msg >();
884 }
885 };
886
887 /*!
888 * \since
889 * v.5.5.4
890 *
891 * \brief A helper for allocate instance of a message.
892 */
893 template< typename Msg, typename... Args >
894 auto
make_message_instance(Args &&...args)895 make_message_instance( Args &&... args )
896 -> std::unique_ptr< typename message_payload_type< Msg >::envelope_type >
897 {
898 return make_message_instance_impl<
899 is_signal< Msg >::value, Msg
900 >::make( std::forward< Args >( args )... );
901 }
902
903 } /* namespace details */
904
905 namespace message_limit
906 {
907
908 struct control_block_t;
909
910 //
911 // any_unspecified_message
912 //
913
914 /*!
915 * \brief A special mark to be used for default limits.
916 *
917 * \since
918 * v.5.7.1
919 */
920 class SO_5_TYPE any_unspecified_message final
921 {
922 // Instances of that type can't be created.
923 ~any_unspecified_message();
924 any_unspecified_message();
925 };
926
927 namespace impl
928 {
929
930 class action_msg_tracer_t;
931
932 } /* namespace impl */
933
934 /*!
935 * \since
936 * v.5.5.4
937 *
938 * \brief Description of context for overlimit action.
939 */
940 struct overlimit_context_t
941 {
942 //! ID of mbox which is used for message delivery.
943 /*!
944 * Added in v.5.5.23 because it is necessary for
945 * so_5::enveloped_msg::handling_context_t.
946 */
947 const mbox_id_t m_mbox_id;
948
949 //! Receiver of the message or service request.
950 const agent_t & m_receiver;
951
952 //! Control block for message limit.
953 const control_block_t & m_limit;
954
955 //! The current deep of overlimit reaction recursion.
956 const unsigned int m_reaction_deep;
957
958 //! Type of message to be delivered.
959 const std::type_index & m_msg_type;
960
961 //! A message or service request to be delivered.
962 const message_ref_t & m_message;
963
964 /*!
965 * \since
966 * v.5.5.9
967 *
968 * \brief An optional pointer to tracer object for
969 * message delivery tracing.
970 *
971 * \note Value nullptr means that message delivery tracing
972 * is not used.
973 */
974 const impl::action_msg_tracer_t * m_msg_tracer;
975
976 //! Initializing constructor.
977 inline
overlimit_context_tso_5::message_limit::overlimit_context_t978 overlimit_context_t(
979 mbox_id_t mbox_id,
980 const agent_t & receiver,
981 const control_block_t & limit,
982 unsigned int reaction_deep,
983 const std::type_index & msg_type,
984 const message_ref_t & message,
985 const impl::action_msg_tracer_t * msg_tracer )
986 : m_mbox_id( mbox_id )
987 , m_receiver( receiver )
988 , m_limit( limit )
989 , m_reaction_deep( reaction_deep )
990 , m_msg_type( msg_type )
991 , m_message( message )
992 , m_msg_tracer{ msg_tracer }
993 {}
994 };
995
996 //
997 // action_t
998 //
999 /*!
1000 * \since
1001 * v.5.5.4
1002 *
1003 * \brief A type for reaction of message overlimit.
1004 */
1005 using action_t = std::function< void(const overlimit_context_t&) >;
1006
1007 //
1008 // control_block_t
1009 //
1010 /*!
1011 * \since
1012 * v.5.5.4
1013 *
1014 * \brief A control block for one message limit.
1015 */
1016 struct control_block_t
1017 {
1018 //! Limit value.
1019 unsigned int m_limit;
1020
1021 //! The current count of the messages of that type.
1022 mutable std::atomic_uint m_count;
1023
1024 //! Limit overflow reaction.
1025 action_t m_action;
1026
1027 //! Initializing constructor.
control_block_tso_5::message_limit::control_block_t1028 control_block_t(
1029 unsigned int limit,
1030 action_t action )
1031 : m_limit( limit )
1032 , m_action( std::move( action ) )
1033 {
1034 m_count = 0;
1035 }
1036
1037 //! Copy constructor.
control_block_tso_5::message_limit::control_block_t1038 control_block_t(
1039 const control_block_t & o )
1040 : m_limit( o.m_limit )
1041 , m_action( o.m_action )
1042 {
1043 m_count.store(
1044 o.m_count.load( std::memory_order_acquire ),
1045 std::memory_order_release );
1046 }
1047
1048 //! Copy operator.
1049 control_block_t &
operator =so_5::message_limit::control_block_t1050 operator=( const control_block_t & o )
1051 {
1052 m_limit = o.m_limit;
1053 m_count.store(
1054 o.m_count.load( std::memory_order_acquire ),
1055 std::memory_order_release );
1056 m_action = o.m_action;
1057
1058 return *this;
1059 }
1060
1061 //! A special indicator about absence of control_block.
1062 inline static const control_block_t *
noneso_5::message_limit::control_block_t1063 none() { return nullptr; }
1064
1065 //! A safe decrement of message count with respect to absence of limit
1066 //! for a message.
1067 inline static void
decrementso_5::message_limit::control_block_t1068 decrement( const control_block_t * limit )
1069 {
1070 if( limit )
1071 --(limit->m_count);
1072 }
1073 };
1074
1075 } /* namespace message_limit */
1076
1077 } /* namespace so_5 */
1078
1079