25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
10 KiB

  1. #pragma once
  2. #include <ecs/config.h>
  3. #include <ecs/tag/system.h>
  4. #include <ecs/context/context.fwd.h>
  5. #include <ecs/core/utils/thread_pool/task_queue.h>
  6. namespace ecs {
  7. namespace core {
  8. namespace system {
  9. namespace scheduler {
  10. namespace detail
  11. {
  12. /**
  13. * meta data to store for each system instance
  14. */
  15. struct instance_meta_data_t
  16. {
  17. ssize_t thread_id = -1;
  18. };
  19. /**
  20. * struct to wrap some system meta data
  21. */
  22. template<
  23. typename T_system_tag,
  24. typename T_execute,
  25. typename T_dependency_ids>
  26. struct dependency_item_t
  27. {
  28. using system_tag_type = T_system_tag;
  29. using execute_type = T_execute;
  30. using dependency_ids_type = T_dependency_ids;
  31. system_tag_type tag; //!< tag of system this dependency element represents
  32. execute_type execute; //!< boolean value to determine if the system should be executed or not
  33. dependency_ids_type dependency_ids; //!< list of system IDs that depends on this system/item
  34. };
  35. /**
  36. * defines a task to be executed (represents a system to execute in the scheduler)
  37. *
  38. * @tparam T_dependency_item dependency item type for this task
  39. * @tparam T_dependent_ids id types of tasks that depends on this task
  40. */
  41. template<
  42. typename T_dependency_item,
  43. typename T_dependent_ids>
  44. struct task_t
  45. {
  46. public:
  47. using dependency_item_type = T_dependency_item;
  48. using dependent_ids_type = T_dependent_ids;
  49. using this_type = task_t<dependency_item_type, dependent_ids_type>;
  50. private:
  51. std::atomic<size_t> _dependency_count;
  52. public:
  53. mp::unwrap_t<dependency_item_type> dependency_item;
  54. /**
  55. * constructor
  56. */
  57. inline task_t();
  58. /**
  59. * get the number unfinished tasks, this task depends on
  60. */
  61. inline size_t dependency_count() const;
  62. /**
  63. * decrepent the unfished task counter
  64. *
  65. * @retval TRUE if all tasks, this task depends on, are finished
  66. * @retval FALSE if at least on task, this task depends on, is not finished
  67. */
  68. inline bool decrement_and_check();
  69. /**
  70. * execute the passed function for task ID that depends on this task
  71. *
  72. * @tparam T_func function type to execute
  73. *
  74. * @param func function to execute
  75. */
  76. template<typename T_func>
  77. constexpr decltype(auto) for_dependent_ids(T_func&& func) const noexcept;
  78. };
  79. /**
  80. * predicate type to create a list of task IDs that depends on the given task
  81. */
  82. struct dependent_ids_t
  83. {
  84. /**
  85. * execute the predicate
  86. *
  87. * @tparam T_dependency_items list of dependency items
  88. * @tparam T_dependency_item dependency item to get taks IDs for, that depends on that item
  89. *
  90. * @return list of task IDs that depends on the given dependency item
  91. */
  92. template<typename T_dependency_items, typename T_dependency_item>
  93. constexpr decltype(auto) operator()(T_dependency_items, T_dependency_item) const noexcept;
  94. };
  95. /**
  96. * predicate type to create a list of tasks
  97. */
  98. struct make_tasks_t
  99. {
  100. /**
  101. * execute the predicate
  102. *
  103. * @tparam T_dependency_items list of dependency items to create tasks from
  104. *
  105. * @return list of tasks
  106. */
  107. template<typename T_dependency_items>
  108. constexpr decltype(auto) operator()(T_dependency_items) const noexcept;
  109. };
  110. /**
  111. * extention of the normal counter_blocker to handle tasks to be executed in the context of the main thread
  112. */
  113. struct task_counter_blocker_t
  114. : public utils::counter_blocker
  115. {
  116. private:
  117. utils::task_queue _tasks; //!< tasks to execute in the main thread
  118. public:
  119. using utils::counter_blocker::counter_blocker;
  120. /**
  121. * enqueue a new task inside the task list
  122. *
  123. * @tparam T_task type of the task
  124. *
  125. * @param task task to execute
  126. */
  127. template<typename T_task>
  128. inline void post(T_task&& task);
  129. /**
  130. * execute all tasks stored in the queue
  131. */
  132. inline void process();
  133. };
  134. /**
  135. * defines a group of tasks to execute with
  136. *
  137. * @tparam T_context context type
  138. * @tparam T_dependency_items list of dependency items
  139. */
  140. template<typename T_context, typename T_dependency_items>
  141. struct task_group_t
  142. {
  143. public:
  144. using context_type = T_context;
  145. using dependency_items_type = T_dependency_items;
  146. using this_type = task_group_t<context_type, dependency_items_type>;
  147. private:
  148. using task_types = mp::decay_t<decltype((make_tasks_t { })(dependency_items_type { }))>;
  149. using tasks_tuple_type = mp::list::unwrap_t<hana::tuple, task_types>;
  150. private:
  151. context_type& _context; //!< context to use for system execution
  152. task_counter_blocker_t& _counter; //!< counter to track running tasks
  153. tasks_tuple_type _tasks; //!< tuple of all tasks
  154. public:
  155. /**
  156. * constructor
  157. *
  158. * @param p_context context to use for system execution
  159. * @param p_counter counter to track running tasks
  160. */
  161. inline task_group_t(context_type& p_context, task_counter_blocker_t& p_counter);
  162. /**
  163. * start the given task
  164. *
  165. * @tparam T_task_id id type of the task to execute
  166. * @tparam T_func overloaded function type to execute system with
  167. *
  168. * @param id id of task to execute
  169. * @param func overloaded function to execute system with
  170. */
  171. template<typename T_task_id, typename T_func>
  172. inline void start_task(T_task_id id, T_func&& func);
  173. private:
  174. /**
  175. * execute the task using the thread pool
  176. *
  177. * @tparam T_task_id id type of task to execute
  178. * @tparam T_func overloaded function type to execute system with
  179. *
  180. * @param func overloaded function to execute system with
  181. */
  182. template<typename T_task_id, typename T_func>
  183. inline void post_task_in_thread_pool(T_task_id, T_func&& func);
  184. /**
  185. * execute the actual task using the passed overloaded function
  186. *
  187. * @tparam T_task_id id type of task to execute
  188. * @tparam T_func overloaded function type to execute system with
  189. *
  190. * @param func overloaded function to execute system with
  191. */
  192. template<typename T_task_id, typename T_func>
  193. inline void execute_task(T_task_id, T_func&& func);
  194. /**
  195. * update the dependencies of the current task and start the next task
  196. *
  197. * @tparam T_task_id id type of task to update dependencies for
  198. * @tparam T_func overloaded function type to execute system with
  199. *
  200. * @param func overloaded function to execute system with
  201. */
  202. template<typename T_task_id, typename T_func>
  203. inline void check_and_start_dependencies(T_task_id, T_func&& func);
  204. };
  205. /**
  206. * create a list of dependency items
  207. *
  208. * @tparam T_system_signature_list system signature list type
  209. * @tparam T_system_tag_list list of system tag types
  210. *
  211. * @return list of dependency items
  212. */
  213. template<typename T_system_signature_list, typename T_system_tag_list>
  214. constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept;
  215. /**
  216. * get a list of independent items from the passed dependency list
  217. *
  218. * @tparam T_dependency_list dependency item list to get independent items from
  219. *
  220. * @return list of independent items
  221. */
  222. template<typename T_dependency_list>
  223. constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept;
  224. }
  225. /**
  226. * scheduler that resolves the dependencies between systems and then executes the systems in a save way in parallel
  227. *
  228. * @tparam T_settings settings type the environment is configured with
  229. */
  230. template<typename T_settings>
  231. struct atomic_counter
  232. {
  233. public:
  234. using settings_type = T_settings;
  235. using context_type = ::ecs::context::type<settings_type>;
  236. using instance_meta_data_type = detail::instance_meta_data_t;
  237. private:
  238. context_type& _context;
  239. public:
  240. /**
  241. * constructor
  242. *
  243. * @param p_context context to use for system exeution
  244. */
  245. inline atomic_counter(context_type& p_context);
  246. /**
  247. * execute the systems for that system tags are passed
  248. *
  249. * @tparam T_system_tag_list list of system tag type to execute systems for
  250. * @tparam T_func overloaded function type to use for system execution
  251. *
  252. * @param stl list of system tags to execute systems for
  253. * @param func overloaded function to use for system execution
  254. */
  255. template<typename T_system_tag_list, typename T_func>
  256. inline void execute(T_system_tag_list stl, T_func&& func);
  257. };
  258. } } } }