SObjectizer-5 Extra
Loading...
Searching...
No Matches
simple_not_mtsafe.hpp
Go to the documentation of this file.
1/*!
2 * \file
3 * \brief Implementation of Asio-based simple not thread safe
4 * environment infrastructure.
5 */
6
7#pragma once
8
9#include <so_5_extra/env_infrastructures/asio/impl/common.hpp>
10
11#include <so_5/version.hpp>
12#if SO_5_VERSION < SO_5_VERSION_MAKE(5u, 8u, 0u)
13#error "SObjectizer-5.8.0 is required"
14#endif
15
16#include <so_5/impl/st_env_infrastructure_reuse.hpp>
17#include <so_5/impl/internal_env_iface.hpp>
18#include <so_5/details/sync_helpers.hpp>
19#include <so_5/details/at_scope_exit.hpp>
20#include <so_5/details/invoke_noexcept_code.hpp>
21
22#include <asio.hpp>
23
24#include <string_view>
25
26namespace so_5 {
27
28namespace extra {
29
30namespace env_infrastructures {
31
32namespace asio {
33
35
36namespace impl {
37
38//! A short name for namespace with reusable stuff.
40
41//! A short name for namespace with common stuff.
42/*!
43 * \since
44 * v.1.0.2
45 */
46namespace asio_common = ::so_5::extra::env_infrastructures::asio::common;
47
48//
49// shutdown_status_t
50//
52
53//
54// coop_repo_t
55//
56/*!
57 * \brief Implementation of coop_repository for
58 * simple thread-safe single-threaded environment infrastructure.
59 */
61
62//
63// stats_controller_t
64//
65/*!
66 * \brief Implementation of stats_controller for that type of
67 * single-threaded environment.
68 */
71
72//
73// event_queue_impl_t
74//
75/*!
76 * \brief Implementation of event_queue interface for the default dispatcher.
77 *
78 * \tparam Activity_Tracker A type for tracking work thread activity.
79 */
80template< typename Activity_Tracker >
82 {
83 public :
84 //! Type for representation of statistical data for this event queue.
85 struct stats_t
86 {
87 //! The current size of the demands queue.
89 };
90
91 //! Initializing constructor.
93 //! Asio's io_context to be used for dispatching.
95 //! Actual activity tracker.
99 {}
100
101 void
103 {
104 ::asio::post(
105 m_io_svc.get(),
106 [this, d = std::move(demand)]() mutable {
107 // Statistics must be updated.
109
110 // The demand can be handled now.
111 // With working time tracking.
113 {
114 // For the case if call_handler will throw.
115 const auto stopper = ::so_5::details::at_scope_exit(
116 [this]{ m_activity_tracker.get().work_stopped(); });
117
119 }
120
121 // If there is no any pending demands then
122 // waiting must be started.
125 } );
126
128 // Waiting must be stopped because we have received an event.
130
131 // Increment demands count only if post doesn't throw.
133 }
134
135 void
137 {
138 // Just delegate to the ordinary push().
139 this->push( std::move(demand) );
140 }
141
142 void
144 {
145 // Just delegate to the ordinary push() despite
146 // the fact that push() isn't noexcept.
147 this->push( std::move(demand) );
148 }
149
150 //! Notification that event queue work is started.
151 void
153 //! ID of the main working thread.
155 {
157
158 // There is no any pending demand now. We can start counting
159 // the waiting time.
161 }
162
163 //! Get the current statistics.
164 stats_t
165 query_stats() const noexcept
166 {
167 return m_stats;
168 }
169
170 private :
173
176 };
177
178//
179// disp_ds_name_parts_t
180//
181/*!
182 * \brief A class with major part of dispatcher name.
183 */
184struct disp_ds_name_parts_t final
185 {
186 static constexpr std::string_view
187 disp_type_part() noexcept { return { "asio_not_mtsafe" }; }
188 };
189
190//
191// default_dispatcher_t
192//
193/*!
194 * \brief An implementation of dispatcher to be used in
195 * places where default dispatcher is needed.
196 *
197 * \tparam Activity_Tracker a type of activity tracker to be used
198 * for run-time statistics.
199 *
200 * \since
201 * v.1.3.0
202 */
203template< typename Activity_Tracker >
209 {
214
215 public :
221 {
222 // Event queue should be started manually.
223 // We known that the default dispatcher is created on a thread
224 // that will be used for events dispatching.
225 event_queue.get().start( this->thread_id() );
226 }
227 };
228
229//
230// env_infrastructure_t
231//
232/*!
233 * \brief Default implementation of not-thread safe single-threaded environment
234 * infrastructure.
235 *
236 * \attention
237 * This class doesn't have any mutex inside.
238 *
239 * \tparam Activity_Tracker A type of activity tracker to be used.
240 */
241template< typename Activity_Tracker >
244 {
245 public :
247 //! Asio's io_context to be used.
249 //! Environment to work in.
251 //! Cooperation action listener.
253 //! Mbox for distribution of run-time stats.
255
256 void
257 launch( env_init_t init_fn ) override;
258
259 /*!
260 * \attention
261 * Since SO-5.8.0 this method should be a noexcept, but
262 * Asio's post() can throw. In that case the whole application
263 * will be terminated.
264 */
265 void
266 stop() noexcept override;
267
268 [[nodiscard]]
270 make_coop(
273
276 coop_unique_holder_t coop ) override;
277
278 void
280 coop_shptr_t coop ) noexcept override;
281
282 bool
284 coop_shptr_t coop_name ) noexcept override;
285
288 const std::type_index & type_wrapper,
289 const message_ref_t & msg,
290 const mbox_t & mbox,
292 std::chrono::steady_clock::duration period ) override;
293
294 void
296 const std::type_index & type_wrapper,
297 const message_ref_t & msg,
298 const mbox_t & mbox,
299 std::chrono::steady_clock::duration pause ) override;
300
302 stats_controller() noexcept override;
303
305 stats_repository() noexcept override;
306
309
311 query_timer_thread_stats() override;
312
314 make_default_disp_binder() override;
315
316 private :
317 //! Asio's io_context to be used.
319
320 //! Actual SObjectizer Environment.
322
323 //! Status of shutdown procedure.
325
326 //! Repository of registered coops.
328
329 //! Actual activity tracker.
330 Activity_Tracker m_activity_tracker;
331
332 //! Event queue which is necessary for the default dispatcher.
334
335 //! Dispatcher to be used as default dispatcher.
336 /*!
337 * \note
338 * Has an actual value only inside launch() method.
339 */
341
342 //! Stats controller for this environment.
344
345 //! Counter of cooperations which are waiting for final deregistration
346 //! step.
347 /*!
348 * It is necessary for building correct run-time stats.
349 */
351
352 //! The pointer to an exception that was thrown during init phase.
353 /*!
354 * This exception is stored inside a callback posted to Asio.
355 * An then this exception will be rethrown from launch() method
356 * after the shutdown of SObjectizer.
357 */
359
360 void
361 run_default_dispatcher_and_go_further( env_init_t init_fn );
362
363 /*!
364 * \note Calls m_io_svc.stop() if necessary.
365 */
366 void
368 };
369
370template< typename Activity_Tracker >
371env_infrastructure_t<Activity_Tracker>::env_infrastructure_t(
372 outliving_reference_t<::asio::io_context> io_svc,
373 environment_t & env,
374 coop_listener_unique_ptr_t coop_listener,
375 mbox_t stats_distribution_mbox )
376 : m_io_svc( io_svc )
377 , m_env( env )
383 {}
384
385template< typename Activity_Tracker >
386void
387env_infrastructure_t<Activity_Tracker>::launch( env_init_t init_fn )
388 {
389 // Post initial operation to Asio event loop.
390 ::asio::post( m_io_svc.get(), [this, init = std::move(init_fn)] {
392 } );
393
394 // Default dispatcher should be destroyed on exit from this function.
397 } );
398
399 // Launch Asio event loop.
400 m_io_svc.get().run();
401
402 // Event loop can be finished in two cases:
403 // 1. SObjectizer has been shut down. We should do nothing in that case.
404 // 2. There is no more work for Asio. But SObjectizer is still working.
405 // In that case a normal shutdown must be initiated.
406 //
407 const auto still_working = [this]{
409 };
410
411 if( still_working() )
412 {
413 // Initiate a shutdown operation.
414 stop();
415 // Run Asio event loop until shutdown will be finished.
416 do
417 {
418 m_io_svc.get().restart();
419 m_io_svc.get().run();
420 }
421 while( still_working() );
422 }
423
425 // Some exception was thrown during initialization.
426 // It should be rethrown.
428 }
429
430template< typename Activity_Tracker >
431void
432env_infrastructure_t<Activity_Tracker>::stop() noexcept
433 {
435 {
437 ::asio::post( m_io_svc.get(), [this] {
438 // Shutdown procedure must be started.
440
441 // All registered cooperations must be deregistered now.
443
445 } );
446 }
447 else
449 }
450
451template< typename Activity_Tracker >
461
462template< typename Activity_Tracker >
466 {
468 }
469
470template< typename Activity_Tracker >
471void
473 coop_shptr_t coop_to_dereg ) noexcept
474 {
476
477 ::asio::post( m_io_svc.get(), [this, coop = std::move(coop_to_dereg)] {
481 } );
482 }
483
484template< typename Activity_Tracker >
485bool
487 coop_shptr_t coop ) noexcept
488 {
491 }
492
493template< typename Activity_Tracker >
496 const std::type_index & type_index,
497 const message_ref_t & msg,
498 const mbox_t & mbox,
501 {
502 using namespace asio_common;
503
506 {
509 m_io_svc.get(),
511 msg,
512 mbox,
513 period ) };
514
517
519 }
520 else
521 {
524 m_io_svc.get(),
526 msg,
527 mbox ) };
528
531
533 }
534
535 return result;
536 }
537
538template< typename Activity_Tracker >
539void
541 const std::type_index & type_index,
542 const message_ref_t & msg,
543 const mbox_t & mbox,
544 std::chrono::steady_clock::duration pause )
545 {
546 using namespace asio_common;
547
550 m_io_svc.get(),
552 msg,
553 mbox ) };
554
556 }
557
558template< typename Activity_Tracker >
560env_infrastructure_t<Activity_Tracker>::stats_controller() noexcept
561 {
562 return m_stats_controller;
563 }
564
565template< typename Activity_Tracker >
567env_infrastructure_t<Activity_Tracker>::stats_repository() noexcept
568 {
569 return m_stats_controller;
570 }
571
572template< typename Activity_Tracker >
584
585template< typename Activity_Tracker >
588 {
589 // Note: this type of environment_infrastructure doesn't support
590 // statistics for timers.
591 return { 0, 0 };
592 }
593
594template< typename Activity_Tracker >
597 {
598 return { m_default_disp };
599 }
600
601template< typename Activity_Tracker >
602void
604 env_init_t init_fn )
605 {
606 try
607 {
613
614 // User-supplied init can be called now.
615 init_fn();
616 }
617 catch(...)
618 {
619 // We can't restore if the following fragment throws and exception.
621 // The current exception should be stored to be
622 // rethrown later.
624
625 // SObjectizer's shutdown should be initiated.
626 stop();
627
628 // NOTE: pointer to the default dispatcher will be dropped
629 // in launch() method.
630 } );
631 }
632 }
633
634template< typename Activity_Tracker >
635void
637 {
639 {
640 // If there is no more live coops then shutdown must be
641 // completed.
643 {
645 // Asio's event loop must be broken here!
646 m_io_svc.get().stop();
647 }
648 }
649 }
650
651//
652// ensure_autoshutdown_enabled
653//
654/*!
655 * Throws an exception if autoshutdown feature is disabled.
656 */
657void
659 const environment_params_t & env_params )
660 {
661 if( env_params.autoshutdown_disabled() )
662 SO_5_THROW_EXCEPTION( rc_autoshutdown_must_be_enabled,
663 "autoshutdown feature must be enabled for "
664 "so_5::env_infrastructures::simple_not_mtsafe" );
665 }
666
667} /* namespace impl */
668
669//
670// factory
671//
672/*!
673 * \brief A factory for creation of environment infrastructure based on
674 * Asio's event loop.
675 *
676 * \attention
677 * This environment infrastructure is not a thread safe.
678 *
679 * Usage example:
680 * \code
681int main()
682{
683 asio::io_context io_svc;
684
685 so_5::launch( [](so_5::environment_t & env) {
686 ... // Some initialization stuff.
687 },
688 [&io_svc](so_5::environment_params_t & params) {
689 using asio_env = so_5::extra::env_infrastructures::asio::simple_not_mtsafe;
690
691 params.infrastructure_factory( asio_env::factory(io_svc) );
692 } );
693
694 return 0;
695}
696 * \endcode
697 */
700 {
701 using namespace impl;
702
703 return [&io_svc](
704 environment_t & env,
705 environment_params_t & env_params,
706 mbox_t stats_distribution_mbox )
707 {
708 ensure_autoshutdown_enabled( env_params );
709
710 environment_infrastructure_t * obj = nullptr;
711
712 // Create environment infrastructure object in dependence of
713 // work thread activity tracking flag.
714 const auto tracking = env_params.work_thread_activity_tracking();
715 if( work_thread_activity_tracking_t::on == tracking )
716 obj = new env_infrastructure_t< reusable::real_activity_tracker_t >(
717 outliving_mutable(io_svc),
718 env,
719 env_params.so5_giveout_coop_listener(),
720 std::move(stats_distribution_mbox) );
721 else
722 obj = new env_infrastructure_t< reusable::fake_activity_tracker_t >(
723 outliving_mutable(io_svc),
724 env,
725 env_params.so5_giveout_coop_listener(),
726 std::move(stats_distribution_mbox) );
727
728 return environment_infrastructure_unique_ptr_t(
729 obj,
730 environment_infrastructure_t::default_deleter() );
731 };
732 }
733
734} /* namespace simple_not_mtsafe */
735
736} /* namespace asio */
737
738} /* namespace env_infrastructures */
739
740} /* namespace extra */
741
742} /* namespace so_5 */
default_dispatcher_t(outliving_reference_t< environment_t > env, outliving_reference_t< event_queue_impl_t< Activity_Tracker > > event_queue, outliving_reference_t< Activity_Tracker > activity_tracker)
Default implementation of not-thread safe single-threaded environment infrastructure.
outliving_reference_t< ::asio::io_context > m_io_svc
Asio's io_context to be used.
so_5::environment_infrastructure_t::coop_repository_stats_t query_coop_repository_stats() override
so_5::timer_id_t schedule_timer(const std::type_index &type_wrapper, const message_ref_t &msg, const mbox_t &mbox, std::chrono::steady_clock::duration pause, std::chrono::steady_clock::duration period) override
std::size_t m_final_dereg_coop_count
Counter of cooperations which are waiting for final deregistration step.
coop_unique_holder_t make_coop(coop_handle_t parent, disp_binder_shptr_t default_binder) override
std::shared_ptr< default_dispatcher_t< Activity_Tracker > > m_default_disp
Dispatcher to be used as default dispatcher.
std::exception_ptr m_exception_from_init
The pointer to an exception that was thrown during init phase.
void single_timer(const std::type_index &type_wrapper, const message_ref_t &msg, const mbox_t &mbox, std::chrono::steady_clock::duration pause) override
event_queue_impl_t< Activity_Tracker > m_event_queue
Event queue which is necessary for the default dispatcher.
event_queue_impl_t(outliving_reference_t<::asio::io_context > io_svc, outliving_reference_t< Activity_Tracker > activity_tracker)
Initializing constructor.
void ensure_autoshutdown_enabled(const environment_params_t &env_params)
environment_infrastructure_factory_t factory(::asio::io_context &io_svc)
A factory for creation of environment infrastructure based on Asio's event loop.
Ranges for error codes of each submodules.
Definition details.hpp:13