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