supervisor_asio.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #pragma once
  2. //
  3. // Copyright (c) 2019 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  4. //
  5. // Distributed under the MIT Software License
  6. //
  7. #include "rotor/supervisor.h"
  8. #include "supervisor_config_asio.h"
  9. #include "system_context_asio.h"
  10. #include "forwarder.hpp"
  11. #include <boost/asio.hpp>
  12. #include <unordered_map>
  13. #include <memory>
  14. namespace rotor {
  15. namespace asio {
  16. namespace asio = boost::asio;
  17. namespace sys = boost::system;
  18. template <typename Actor, typename Handler, typename ErrHandler> struct forwarder_t;
  19. /** \struct supervisor_asio_t
  20. *
  21. * \brief delivers rotor-messages on top of boost asio event loop
  22. * using `strand` for serialization
  23. *
  24. * The boost::asio `strand` guarantees, that handler, which "belongs" to
  25. * the same `strand` will be executed sequentially. It might be called
  26. * on different threads, however.
  27. *
  28. * The `supervisor_asio_t` uses that advantage to let the messages to
  29. * the supervisor and it's actors be delivered sequentially.
  30. *
  31. * The "sub-supervisors" can be created, but they do not extend the
  32. * sequential executing context, i.e. in the execution sense the
  33. * supervisors are independent.
  34. *
  35. * When there is need to "uplift" the boost::asio low-level event,
  36. * into high-level `rotor` message, the {@link forwarder_t} can be used.
  37. * It uses the `strand` under the hood.
  38. *
  39. * If there is need to change some actor's internals from boost::asio
  40. * handler, the change should be performed in synchronized way, i.e.
  41. * via `strand`.
  42. *
  43. */
  44. struct supervisor_asio_t : public supervisor_t {
  45. /** \struct timer_t
  46. * \brief boos::asio::deadline_timer with timer identity */
  47. struct timer_t : public asio::deadline_timer {
  48. /** \brief timer identity */
  49. timer_id_t timer_id;
  50. /** \brief constructs timer using timer_id and boos asio io_context */
  51. timer_t(timer_id_t timer_id_, asio::io_context &io_context)
  52. : asio::deadline_timer(io_context), timer_id{timer_id_} {}
  53. };
  54. /** \brief unique pointer to timer */
  55. using timer_ptr_t = std::unique_ptr<timer_t>;
  56. /** \brief timer id to timer pointer mapping type */
  57. using timers_map_t = std::unordered_map<std::uint32_t, timer_ptr_t>;
  58. /** \brief constructs new supervisor from parent supervisor, intrusive
  59. * pointer to system context and supervisor config and
  60. * the `parent` supervisor can be null
  61. *
  62. */
  63. supervisor_asio_t(supervisor_t *sup, const supervisor_config_asio_t &config);
  64. virtual address_ptr_t make_address() noexcept override;
  65. virtual void start() noexcept override;
  66. virtual void shutdown() noexcept override;
  67. virtual void enqueue(message_ptr_t message) noexcept override;
  68. virtual void start_timer(const pt::time_duration &send, timer_id_t timer_id) noexcept override;
  69. virtual void cancel_timer(timer_id_t timer_id) noexcept override;
  70. /** \brief callback when an error happen on the timer, identified by timer_id */
  71. virtual void on_timer_error(timer_id_t timer_id, const sys::error_code &ec) noexcept;
  72. /** \brief creates an actor by forwaring `args` to it
  73. *
  74. * The newly created actor belogs to the current supervisor
  75. *
  76. */
  77. template <typename Actor, typename... Args>
  78. intrusive_ptr_t<Actor> create_actor(const pt::time_duration &timeout, Args... args) {
  79. return make_actor<Actor>(*this, timeout, std::forward<Args>(args)...);
  80. }
  81. /** \brief an helper for creation {@link forwarder_t} */
  82. template <typename Handler, typename ErrHandler>
  83. auto create_forwarder(Handler &&handler, ErrHandler &&err_handler) {
  84. return forwarder_t{*this, std::move(handler), std::move(err_handler)};
  85. }
  86. /** \brief an helper for creation {@link forwarder_t} (no-error handler case) */
  87. template <typename Handler> auto create_forwarder(Handler &&handler) {
  88. return forwarder_t{*this, std::move(handler)};
  89. }
  90. /** \brief retunrns an reference to boos::asio systerm context
  91. *
  92. * It might be useful to get `boost::asio::io_context&`, i.e. to create socket.
  93. *
  94. */
  95. inline system_context_asio_t &get_asio_context() noexcept { return static_cast<system_context_asio_t &>(*context); }
  96. /** \brief returns exeuction strand */
  97. inline asio::io_context::strand &get_strand() noexcept { return *strand; }
  98. /** \brief timer id to timer pointer mapping */
  99. timers_map_t timers_map;
  100. /** \brief config for the supervisor */
  101. supervisor_config_asio_t::strand_ptr_t strand;
  102. };
  103. template <typename Actor> inline boost::asio::io_context::strand &get_strand(Actor &actor) {
  104. return actor.get_strand();
  105. }
  106. } // namespace asio
  107. } // namespace rotor