supervisor.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // SPDX-License-Identifier: MIT
  2. // SPDX-FileCopyrightText: 2022 Ivan Baidakou
  3. #pragma once
  4. #include "actor.hpp"
  5. #include "message.hpp"
  6. #include "planner.hpp"
  7. #include "queue.hpp"
  8. #include "rotor-light-bsp.h"
  9. #include <tuple>
  10. #include <type_traits>
  11. #include <utility>
  12. namespace rotor_light {
  13. namespace details {
  14. /** \struct ChildState
  15. * \brief wrapper for holding child states in supervisor */
  16. struct ChildState {
  17. /** from which state actor is asked to shut self down */
  18. State down_state = State::off;
  19. };
  20. } // namespace details
  21. /** \struct SupervisorBase
  22. * \brief base interface and implementation for all supervisors */
  23. struct SupervisorBase : ActorBase {
  24. friend struct ActorBase;
  25. /** the minimum amount of handles, which should
  26. * a derived actor class pre-allocate */
  27. static constexpr size_t min_handlers_amount =
  28. ActorBase::min_handlers_amount + 2;
  29. /** convenient alias to the parent struct */
  30. using Parent = ActorBase;
  31. /** ctor */
  32. SupervisorBase(char *backends, size_t backends_count, ActorBase **actors,
  33. details::ChildState *states, size_t actors_count);
  34. /** returns meta-queue */
  35. inline QueueBase *get_queue() { return queue; }
  36. void initialize() override;
  37. /**
  38. * @brief starts all actors (initialize, wait confirmation etc.)
  39. * @param poll_timer whether `RefreshTime` message should be
  40. * send self on idle. When it is, the `process` method will never
  41. * exit in normal circumstances
  42. */
  43. void start(bool poll_timer = false);
  44. /**
  45. * Binds context to the supervisor and all its children. Permanent
  46. * actorIds are created and assigned during this phase.
  47. *
  48. * This method should be invoked only once in lifetime
  49. * of actors.
  50. *
  51. */
  52. virtual void bind(Context &context, ActorId value = 0);
  53. uint8_t bind(ActorId initial_value, SupervisorBase *supervisor,
  54. Context &context) override;
  55. /**
  56. *
  57. * "Main loop" of the framework, which does messages dispatching.
  58. * As the new messages are usually generated during messages dispatching
  59. * this method never exits under normal circumstances.
  60. *
  61. * It can exit in two cases:
  62. *
  63. * 1. There are no more messages. This might happen if the endless
  64. * timer polling is enabled in `start` method. This means, that
  65. * you intentionally do that, e.g. to enter into a sleep mode and do
  66. * some power-saving before the next event. Platform-specific
  67. * sleep and awake codes should be implemented to achive that.
  68. *
  69. * 2. Supervisor has terminated, and there is no sense of further
  70. * restart attempts. Usually that means, that supervisor did its
  71. * best, all restarts (having sense) has been applied without effect,
  72. * and nothing can be done, possibly due to unrecoverable hardware
  73. * failure; or the supervisor has terminated due to its job is done.
  74. * Usually that means board restart or poweroff.
  75. *
  76. */
  77. void process();
  78. // handlers
  79. void advance_init() override;
  80. void advance_start() override;
  81. void advance_stop() override;
  82. /** returns pointer to the planner */
  83. inline PlannerBase *get_planner() { return planner; }
  84. protected:
  85. /**
  86. * refreshes time, processes expired time events and re-schedules
  87. * `RefreshTime` message
  88. *
  89. * The method can be overriden to do something useful "on idle".
  90. *
  91. */
  92. virtual void on_refhesh_timer(message::RefreshTime &);
  93. /** pointer to child actor holding pointers */
  94. ActorBase **actors;
  95. /** pointer to child actor states */
  96. details::ChildState *states;
  97. /** the amount of child actors */
  98. size_t actors_count;
  99. /** pointer to the master queue */
  100. QueueBase *queue;
  101. /** pointer to the planner */
  102. PlannerBase *planner;
  103. /** function pointer, which can return "now" */
  104. NowFunction now;
  105. private:
  106. void on_state_change_ack(message::ChangeStateAck &);
  107. void on_child_init_failure(size_t actor_index);
  108. void dispatch(Message &);
  109. void on_child_down(size_t actor_index);
  110. void init_child(size_t actor_index);
  111. void start_actor(size_t actor_index);
  112. size_t process_watchdog();
  113. bool check_child_state(State subject, bool skip_self);
  114. };
  115. /** \struct Supervisor
  116. * \brief convenient templated base class for supervisor, which
  117. * owns (stores) all it's child-actors */
  118. template <size_t HandlersCount, typename... Actors>
  119. struct Supervisor : SupervisorBase {
  120. static_assert(HandlersCount >= SupervisorBase::min_handlers_amount,
  121. "no enough handlers");
  122. Supervisor()
  123. : SupervisorBase(reinterpret_cast<char *>(&backends), HandlersCount,
  124. actors, children_states_holder, children_count + 1) {
  125. actors[0] = this;
  126. fill_actor<0>();
  127. }
  128. /** returns child actor by indes */
  129. template <size_t ChildIndex> auto get_child() {
  130. return &std::get<ChildIndex>(children);
  131. }
  132. protected:
  133. /** heterogenious / type-friendly container for child actors (type) */
  134. using ActorsList = std::tuple<Actors...>;
  135. /** count of child actors */
  136. static constexpr size_t children_count = std::tuple_size_v<ActorsList>;
  137. /** heterogenious / type-friendly container for child actors */
  138. ActorsList children;
  139. /** message handlers storage */
  140. ActorBase::Handler backends[HandlersCount];
  141. /** pointers to actors, including self. Needed to be processed
  142. * uniformly */
  143. ActorBase *actors[children_count + 1];
  144. /** child actors states, including self */
  145. details::ChildState children_states_holder[children_count + 1];
  146. private:
  147. template <size_t ChildIndex> void fill_actor() {
  148. if constexpr (ChildIndex < children_count) {
  149. actors[ChildIndex + 1] = get_child<ChildIndex>();
  150. fill_actor<ChildIndex + 1>();
  151. }
  152. }
  153. };
  154. template <typename Ctx, typename MessageType, typename... Args>
  155. bool ActorBase::send(size_t queue_index, Args... args) {
  156. auto &queue = supervisor->queue;
  157. if constexpr (std::is_same_v<Ctx, ctx::thread>) {
  158. ROTOR_LIGHT_DISABLE_INTERRUPTS();
  159. }
  160. auto result =
  161. queue->put<MessageType>(queue_index, std::forward<Args>(args)...);
  162. if constexpr (std::is_same_v<Ctx, ctx::thread>) {
  163. ROTOR_LIGHT_ENABLE_INTERRUPTS();
  164. }
  165. return result;
  166. }
  167. template <typename Ctx>
  168. EventId ActorBase::add_event(Duration delta, Callback callback, void *data) {
  169. assert(supervisor->now && supervisor->planner);
  170. auto when = supervisor->now() + delta;
  171. return supervisor->planner->add_event<Ctx>(when, callback, data);
  172. }
  173. } // namespace rotor_light