27 #include <type_traits>
58 : handle_(other.handle_)
67 handle_ = other.handle_;
78 [[nodiscard]]
explicit operator bool() const noexcept
80 return handle_ !=
nullptr;
83 [[nodiscard]]
bool done() const noexcept
85 return handle_ ==
nullptr || handle_.done();
93 [[nodiscard]]
bool resume();
96 void destroy() noexcept
98 if (handle_ !=
nullptr) {
111 template<std::
size_t Bytes>
115 static_assert(Bytes > 0U,
116 "tsm: static_coroutine_arena requires non-zero storage");
119 std::size_t alignment) noexcept
121 const std::size_t aligned = align_up(used_, alignment);
122 if (aligned > Bytes || bytes > Bytes - aligned) {
125 used_ = aligned + bytes;
126 return storage_.data() + aligned;
129 [[nodiscard]] std::size_t
used() const noexcept
133 [[nodiscard]] std::size_t
capacity() const noexcept
139 static constexpr std::size_t align_up(std::size_t value,
140 std::size_t alignment) noexcept
142 return (value + alignment - 1U) & ~(alignment - 1U);
145 alignas(std::max_align_t) std::array<unsigned char, Bytes> storage_{};
199 using wake_fn = void (*)(
void*, std::size_t) noexcept;
208 std::size_t) =
delete;
210 template<std::
size_t Bytes>
214 std::size_t frame_limit,
222 allocate_ = [](
void* object,
224 std::size_t alignment) noexcept ->
void* {
226 ->allocate(bytes, alignment);
231 frame_limit_ = frame_limit;
232 scheduler_ = scheduler;
240 std::size_t alignment) noexcept
244 if (bytes > frame_limit_) {
248 if (allocate_ ==
nullptr) {
252 void* storage = allocate_(arena_, bytes, alignment);
253 if (storage ==
nullptr) {
259 [[nodiscard]] std::size_t
task_id() const noexcept
281 return failure_reason_;
304 predicate_ =
nullptr;
305 predicate_object_ =
nullptr;
316 predicate_ =
nullptr;
317 predicate_object_ =
nullptr;
339 if (sleep_ ==
nullptr || !sleep_(scheduler_, task_id_,
ticks)) {
346 if (cancel_sleep_ !=
nullptr && scheduler_ !=
nullptr) {
347 cancel_sleep_(scheduler_, task_id_);
351 template<
typename Object,
typename Predicate>
352 void wait_until(Object
const&
object, Predicate predicate) noexcept
354 predicate_object_ = &object;
362 switch (wait_kind_) {
370 return predicate_ !=
nullptr && predicate_(predicate_object_);
381 predicate_ !=
nullptr && predicate_(predicate_object_);
395 failure_reason_ = reason;
396 predicate_ =
nullptr;
397 predicate_object_ =
nullptr;
409 if (queued_ || wake_ ==
nullptr || scheduler_ ==
nullptr) {
413 wake_(scheduler_, task_id_);
422 using allocate_fn =
void* (*)(
void*, std::size_t, std::size_t) noexcept;
426 allocate_fn allocate_{};
431 void const* predicate_object_{};
432 std::size_t task_id_{};
433 std::size_t instance_id_{};
434 std::size_t frame_limit_{};
436 std::uint32_t generation_{};
443 namespace runtime::detail {
451 template<
typename First,
typename... Rest>
455 if constexpr (std::is_same_v<std::remove_cvref_t<First>,
task_context>) {
468 template<
typename First,
typename... Args>
479 static void*
operator new(std::size_t) =
delete;
481 template<
typename... Args>
482 static void*
operator new(std::size_t bytes, Args&... args) noexcept
487 if (task_ctx ==
nullptr) {
490 return task_ctx->
allocate_frame(bytes,
alignof(std::max_align_t));
493 static void operator delete(
void*) noexcept {}
494 static void operator delete(
void*, std::size_t) noexcept {}
496 template<
typename... Args>
497 static void operator delete(
void*, Args&...) noexcept
501 template<
typename... Args>
502 static void operator delete(
void*, std::size_t, Args&...) noexcept
508 return task{ task::handle_type::from_promise(*
this) };
524 if (
handle.promise().context_ !=
nullptr) {
525 handle.promise().context_->mark_completed();
538 if (context_ !=
nullptr) {
555 if (handle_ ==
nullptr || handle_.done()) {
558 auto& context = handle_.promise().context();
559 if (!context.ready_to_resume()) {
562 context.mark_running();
583 handle.promise().context().mark_ready();
588 [[nodiscard]]
inline yield_awaitable
612 handle.promise().context().sleep_for(
ticks);
616 context.cancel_sleep();
621 [[nodiscard]]
inline sleep_ticks_awaitable
627 [[nodiscard]]
inline sleep_ticks_awaitable
637 [[nodiscard]]
inline sleep_ticks_awaitable
643 [[nodiscard]]
inline sleep_ticks_awaitable
700 handle.promise().context().sleep_for(
ticks);
704 context.cancel_sleep();
709 [[nodiscard]]
inline timeout_ticks_awaitable
715 [[nodiscard]]
inline timeout_ticks_awaitable
721 namespace runtime::detail {
723 template<
typename Awaitable>
728 } -> std::convertible_to<bool>;
734 struct is_timeout_ticks : std::false_type
743 template<
typename Awaitable>
770 : awaitables_(std::move(awaitables)...)
776 return ready_any(std::make_index_sequence<
sizeof...(Awaitables)>{});
781 context_ = &handle.promise().context();
782 suspend_all(handle, std::make_index_sequence<
sizeof...(Awaitables)>{});
788 ready_any(std::make_index_sequence<
sizeof...(Awaitables)>{}));
789 select_timeout_if_due(
790 std::make_index_sequence<
sizeof...(Awaitables)>{});
791 cancel_unselected(std::make_index_sequence<
sizeof...(Awaitables)>{});
796 template<std::size_t... I>
797 [[nodiscard]]
bool ready_any(std::index_sequence<I...>) noexcept
800 ((ready = ready || ready_one<I>()), ...);
804 template<std::
size_t I>
805 [[nodiscard]]
bool ready_one() noexcept
807 if (selected_ != npos) {
817 template<std::size_t... I>
819 std::index_sequence<I...>) noexcept
821 (suspend_one<I>(handle), ...);
824 template<std::
size_t I>
827 if (selected_ == I || std::get<I>(awaitables_).
await_ready()) {
831 std::get<I>(awaitables_).await_suspend(handle);
834 template<std::size_t... I>
835 void select_timeout_if_due(std::index_sequence<I...>) noexcept
837 if (selected_ != npos) {
840 ((select_timeout_index<I>()), ...);
843 template<std::
size_t I>
844 void select_timeout_index() noexcept
846 if constexpr (runtime::detail::is_timeout_ticks<
847 std::tuple_element_t<I, std::tuple<Awaitables...>>>::
849 if (selected_ == npos) {
855 template<std::size_t... I>
856 void cancel_unselected(std::index_sequence<I...>) noexcept
858 if (context_ ==
nullptr || selected_ == npos) {
861 (cancel_one<I>(), ...);
864 template<std::
size_t I>
865 void cancel_one() noexcept
867 if (I != selected_) {
873 static constexpr std::size_t npos =
static_cast<std::size_t
>(-1);
875 std::tuple<Awaitables...> awaitables_;
876 task_context* context_{};
877 std::size_t selected_{
npos };
880 template<
typename... Awaitables>
884 static_assert(
sizeof...(Awaitables) > 0U,
885 "tsm: select requires at least one awaitable");
887 std::forward<Awaitables>(awaitables)...
891 template<
typename Awaitable>
898 template<
typename Awaitable>
906 template<
typename Runtime,
typename Event>
912 , event_(std::forward<Event>(event))
923 accepted_ = runtime_->send_event(std::move(event_));
934 std::decay_t<Event> event_;
938 template<
typename Runtime,
typename Event>
944 , event_(std::forward<Event>(event))
955 accepted_ = runtime_->send_event(std::move(event_));
966 std::decay_t<Event> event_;
970 template<
typename Runtime,
typename Event>
975 std::forward<Event>(event) };
978 template<
typename Event,
typename Runtime,
typename... Args>
982 return send_event(runtime, Event{ std::forward<Args>(args)... });
985 template<
typename Runtime,
typename Event>
991 std::forward<Event>(event),
995 template<
typename Event,
typename Runtime,
typename... Args>
999 return try_send_event(runtime, Event{ std::forward<Args>(args)... });
1002 template<
typename State,
typename Machine>
1007 : machine_(&machine)
1013 return machine_->template active<State>();
1018 handle.promise().context().wait_until(
1019 *machine_, [](
void const*
object) noexcept {
1020 return static_cast<Machine const*
>(object)
1021 ->
template active<State>();
1028 Machine* machine_{};
1031 template<
typename State,
typename Machine>
1038 template<std::
size_t Count>
1041 static constexpr std::size_t
value = Count;
1044 template<std::
size_t Bytes>
1047 static constexpr std::size_t
value = Bytes;
1050 template<std::u
int8_t Priority>
1054 static constexpr std::uint8_t
value = Priority;
1057 template<std::
size_t Count,
typename FrameBytes>
1062 static constexpr std::size_t
count = Count;
1065 static_assert(
count > 0U,
1066 "tsm: dynamic_task_slots requires at least one slot");
1068 "tsm: dynamic_task_slots requires non-zero frame storage");
1071 template<
auto... Entries>
1074 static constexpr std::size_t
size =
sizeof...(Entries);
1077 namespace runtime::detail {
1079 consteval std::size_t
1085 template<std::size_t Count,
typename... Rest>
1086 consteval std::size_t
1092 template<
typename First,
typename... Rest>
1093 consteval std::size_t
1099 consteval std::size_t
1105 template<std::size_t Bytes,
typename... Rest>
1106 consteval std::size_t
1112 template<
typename First,
typename... Rest>
1113 consteval std::size_t
1119 consteval std::uint8_t
1125 template<std::uint8_t Priority,
typename... Rest>
1126 consteval std::uint8_t
1132 template<
typename First,
typename... Rest>
1133 consteval std::uint8_t
1141 template<
auto Entry,
typename... Options>
1155 "tsm: task_def requires at least one instance");
1157 "tsm: task_def requires non-zero frame storage");
1160 template<
typename... TaskDefinitions>
1163 static constexpr std::size_t
size =
sizeof...(TaskDefinitions);
1170 template<
typename Definition,
typename =
void>
1176 template<
typename Definition>
1177 struct task_list_of<Definition, std::void_t<typename Definition::tasks>>
1179 using type =
typename Definition::tasks;
1182 template<
typename Runtime,
typename =
void>
1183 struct runtime_task_list_of
1188 template<
typename Runtime>
1189 struct runtime_task_list_of<
Runtime, std::void_t<typename Runtime::definition>>
1191 using type =
typename task_list_of<typename Runtime::definition>::type;
1194 template<
typename TaskList>
1195 struct task_list_traits;
1197 template<
typename Definition>
1201 Definition::instances;
1202 Definition::frame_bytes;
1205 template<
typename Definition>
1209 Definition::frame_bytes;
1212 template<auto Left, auto Right>
1214 std::remove_cvref_t<decltype(Right)>>;
1216 template<
typename T>
1217 struct task_entry_count
1219 static constexpr std::size_t value = 0U;
1222 template<
auto Entry,
typename... Options>
1223 struct task_entry_count<
tsm::
task_def<Entry, Options...>>
1225 static constexpr std::size_t value =
1229 template<
typename T>
1230 struct task_dynamic_count
1232 static constexpr std::size_t value = 0U;
1235 template<std::
size_t Count,
typename FrameBytes>
1236 struct task_dynamic_count<
tsm::dynamic_task_slots<Count, FrameBytes>>
1238 static constexpr std::size_t value = Count;
1241 template<
typename T>
1242 struct task_frame_total
1244 static constexpr std::size_t value = 0U;
1247 template<
auto Entry,
typename... Options>
1248 struct task_frame_total<
tsm::task_def<Entry, Options...>>
1250 static constexpr std::size_t value =
1255 template<std::
size_t Count,
typename FrameBytes>
1256 struct task_frame_total<
tsm::dynamic_task_slots<Count, FrameBytes>>
1258 static constexpr std::size_t value = Count * FrameBytes::value;
1261 template<
typename... TaskDefinitions>
1262 struct task_list_traits<
tsm::tasks<TaskDefinitions...>>
1264 static constexpr std::size_t task_count =
1266 (task_entry_count<TaskDefinitions>::value +
1267 task_dynamic_count<TaskDefinitions>::value));
1268 static constexpr std::size_t arena_alignment_padding =
1269 task_count * (
alignof(std::max_align_t) - 1U);
1270 static constexpr std::size_t declared_task_count =
1271 (0U + ... + task_entry_count<TaskDefinitions>::value);
1272 static constexpr std::size_t dynamic_task_count =
1273 (0U + ... + task_dynamic_count<TaskDefinitions>::value);
1274 static constexpr std::size_t arena_bytes =
1275 (0U + ... + task_frame_total<TaskDefinitions>::value) +
1276 arena_alignment_padding;
1279 template<
typename Runtime>
1282 using task_list =
typename runtime_task_list_of<Runtime>::type;
1283 using traits = task_list_traits<task_list>;
1285 static constexpr std::size_t task_count = traits::task_count;
1286 static constexpr std::size_t declared_task_count =
1287 traits::declared_task_count;
1288 static constexpr std::size_t dynamic_task_count =
1289 traits::dynamic_task_count;
1290 static constexpr std::size_t arena_bytes = traits::arena_bytes;
1291 static constexpr std::size_t timer_slots = traits::task_count;
1292 static constexpr
bool uses_heap =
false;
1295 template<std::
size_t Capacity>
1299 [[nodiscard]]
bool schedule(std::size_t task_id,
1301 std::uint32_t sequence) noexcept
1303 if (size_ >= Capacity) {
1306 timers_[size_++] = timer_record{ task_id, wake_tick, sequence };
1310 template<
typename Wake>
1315 std::size_t woken{};
1317 std::size_t selected = Capacity;
1318 for (std::size_t i = 0; i < size_; ++i) {
1319 if (timers_[i].wake_tick > now) {
1322 if (selected == Capacity ||
1323 before(timers_[i], timers_[selected])) {
1327 if (selected == Capacity) {
1330 const auto record = timers_[selected];
1331 timers_[selected] = timers_[size_ - 1U];
1333 wake(record.task_id);
1338 [[nodiscard]] std::size_t size() const noexcept
1343 void cancel(std::size_t task_id) noexcept
1345 for (std::size_t i = 0; i < size_; ++i) {
1346 if (timers_[i].task_id != task_id) {
1349 timers_[i] = timers_[size_ - 1U];
1358 std::size_t task_id{};
1360 std::uint32_t sequence{};
1363 static constexpr
bool before(timer_record
const& lhs,
1364 timer_record
const& rhs) noexcept
1366 return lhs.wake_tick < rhs.wake_tick ||
1367 (lhs.wake_tick == rhs.wake_tick && lhs.sequence < rhs.sequence);
1370 std::array<timer_record, Capacity> timers_{};
1371 std::size_t size_{};
1374 template<
typename Runtime,
typename TaskList,
bool PriorityAware = false>
1375 class coroutine_scheduler;
1377 template<
typename Runtime,
bool PriorityAware>
1378 class coroutine_scheduler<
Runtime,
tsm::tasks<>, PriorityAware>
1381 explicit constexpr coroutine_scheduler(
Runtime&) {}
1383 [[nodiscard]]
bool step()
1387 std::size_t run_ready()
1399 std::size_t poll_waiting()
1405 template<
typename Runtime,
bool PriorityAware,
typename... TaskDefinitions>
1406 class coroutine_scheduler<
Runtime,
1407 tsm::tasks<TaskDefinitions...>,
1411 using task_list =
tsm::tasks<TaskDefinitions...>;
1412 static constexpr std::size_t task_count =
1413 task_list_traits<task_list>::task_count;
1414 static constexpr std::size_t arena_bytes =
1415 task_list_traits<task_list>::arena_bytes;
1416 static constexpr std::size_t declared_task_count =
1417 task_list_traits<task_list>::declared_task_count;
1418 static constexpr std::size_t dynamic_task_count =
1419 task_list_traits<task_list>::dynamic_task_count;
1421 explicit coroutine_scheduler(
Runtime& runtime)
1422 : runtime_(&runtime)
1427 bind_all<TaskDefinitions...>();
1431 coroutine_scheduler(coroutine_scheduler
const&) =
delete;
1432 coroutine_scheduler& operator=(coroutine_scheduler
const&) =
delete;
1434 [[nodiscard]]
bool step()
1439 std::size_t task_id{};
1440 while (pop_ready(task_id)) {
1441 auto& context = contexts_[task_id];
1443 context.clear_queued();
1446 context.clear_queued();
1447 return tasks_[task_id].resume();
1452 std::size_t run_ready()
1454 std::size_t resumed{};
1465 now_ += elapsed_ticks;
1466 for (
auto& context : contexts_) {
1467 context.set_now(now_);
1469 static_cast<void>(timers_.wake_due(now_, [
this](std::size_t task_id) {
1470 contexts_[task_id].mark_ready();
1477 return tick(elapsed_ticks.
count());
1480 std::size_t poll_waiting()
1484 std::size_t
ready{};
1485 for (
auto& context : contexts_) {
1486 if (context.predicate_ready()) {
1487 context.mark_ready();
1494 void enqueue(std::size_t task_id) noexcept
1496 if (ready_size_ >= ready_queue_.size()) {
1497 contexts_[task_id].mark_failed(
1501 ready_queue_[ready_push_] = task_id;
1502 ready_push_ = next_ready(ready_push_);
1508 start_all_declared<TaskDefinitions...>();
1511 template<auto Entry, std::
size_t Instance = 0U>
1515 return start_entry<
Entry, Instance, TaskDefinitions...>(base);
1518 template<
auto Entry,
typename... Args>
1524 for (std::size_t task_id = declared_task_count; task_id < task_count;
1538 "tsm: spawned task must return tsm::task and accept "
1539 "(tsm::task_context&, Runtime&, std::size_t, args...)");
1540 contexts_[task_id].prepare_start();
1541 tasks_[task_id] =
Entry(contexts_[task_id],
1543 task_id - declared_task_count,
1544 std::forward<Args>(args)...);
1545 if (!tasks_[task_id]) {
1546 return spawn_failure(contexts_[task_id]);
1548 contexts_[task_id].mark_ready();
1555 template<auto Entry, std::
size_t Instance = 0U>
1559 std::size_t task_id{};
1560 if (!find_entry<Entry, Instance, TaskDefinitions...>(base, task_id)) {
1563 return contexts_[task_id].status();
1566 template<auto Entry, std::
size_t Instance = 0U>
1570 std::size_t task_id{};
1571 if (!find_entry<Entry, Instance, TaskDefinitions...>(base, task_id)) {
1574 return contexts_[task_id].failure_reason();
1577 template<auto Entry, std::
size_t Instance = 0U>
1578 [[nodiscard]]
bool cancel() noexcept
1581 std::size_t task_id{};
1582 if (!find_entry<Entry, Instance, TaskDefinitions...>(base, task_id)) {
1585 contexts_[task_id].cancel();
1589 void cancel_all() noexcept
1591 for (
auto& context : contexts_) {
1598 task_context
const& context) noexcept
1605 static constexpr std::size_t next_ready(std::size_t index) noexcept
1607 return (index + 1U) % task_count;
1610 [[nodiscard]]
bool pop_ready(std::size_t& task_id) noexcept
1612 if (ready_size_ == 0U) {
1615 if constexpr (PriorityAware) {
1616 return pop_highest_priority(task_id);
1618 task_id = ready_queue_[ready_pop_];
1619 ready_pop_ = next_ready(ready_pop_);
1624 [[nodiscard]]
bool pop_highest_priority(std::size_t& task_id) noexcept
1626 std::size_t selected_offset{};
1627 std::size_t selected_task = ready_queue_[ready_pop_];
1628 auto selected_task_priority = priorities_[selected_task];
1629 for (std::size_t offset = 1U; offset < ready_size_; ++offset) {
1630 const auto candidate = ready_queue_[ready_index(offset)];
1631 const auto candidate_priority = priorities_[candidate];
1632 if (candidate_priority > selected_task_priority) {
1633 selected_offset = offset;
1634 selected_task = candidate;
1635 selected_task_priority = candidate_priority;
1639 task_id = selected_task;
1640 for (std::size_t offset = selected_offset; offset + 1U < ready_size_;
1642 ready_queue_[ready_index(offset)] =
1643 ready_queue_[ready_index(offset + 1U)];
1645 ready_push_ = ready_index(ready_size_ - 1U);
1650 [[nodiscard]] std::size_t ready_index(std::size_t offset)
const noexcept
1652 return (ready_pop_ + offset) % task_count;
1655 static void wake_task(
void* scheduler, std::size_t task_id) noexcept
1657 static_cast<coroutine_scheduler*
>(scheduler)->enqueue(task_id);
1660 static bool sleep_task(
void* scheduler,
1661 std::size_t task_id,
1664 auto*
self =
static_cast<coroutine_scheduler*
>(scheduler);
1665 return self->timers_.schedule(
1666 task_id, self->now_ +
ticks, self->timer_sequence_++);
1669 static void cancel_sleep_task(
void* scheduler, std::size_t task_id) noexcept
1671 static_cast<coroutine_scheduler*
>(scheduler)->timers_.cancel(task_id);
1674 template<
typename... Definitions>
1677 std::size_t index{};
1678 (bind_definition<Definitions>(index), ...);
1681 template<
typename Definition>
1682 void bind_definition(std::size_t& index)
1686 if constexpr (declared_task_definition<Definition>) {
1687 bind_task_definition<Definition>(index);
1688 }
else if constexpr (dynamic_task_definition<Definition>) {
1689 bind_dynamic_slots<Definition>(index);
1693 template<
typename Definition>
1694 void bind_task_definition(std::size_t& index)
1696 for (std::size_t instance = 0; instance < Definition::instances;
1698 priorities_[index] = Definition::priority;
1699 contexts_[index].bind(arena_,
1702 Definition::frame_bytes,
1711 template<
typename Definition>
1712 void bind_dynamic_slots(std::size_t& index)
1714 for (std::size_t instance = 0; instance < Definition::count;
1716 contexts_[index].bind(arena_,
1719 Definition::frame_bytes,
1728 template<
typename Definition>
1729 [[nodiscard]]
spawn_result start_definition_instance(std::size_t task_id,
1730 std::size_t instance)
1736 static_assert(std::is_invocable_r_v<
tsm::task,
1737 decltype(Definition::entry),
1741 "tsm: task entry must return tsm::task and accept "
1742 "(tsm::task_context&, Runtime&, std::size_t)");
1743 contexts_[task_id].prepare_start();
1745 Definition::entry(contexts_[task_id], *runtime_, instance);
1746 if (!tasks_[task_id]) {
1747 return spawn_failure(contexts_[task_id]);
1749 contexts_[task_id].mark_ready();
1753 template<
typename... Definitions>
1754 void start_all_declared()
1757 (start_all_for_definition<Definitions>(base), ...);
1760 template<
typename Definition>
1761 void start_all_for_definition(std::size_t& base)
1763 if constexpr (declared_task_definition<Definition>) {
1764 for (std::size_t instance = 0; instance < Definition::instances;
1766 static_cast<void>(start_definition_instance<Definition>(
1767 base + instance, instance));
1769 base += Definition::instances;
1770 }
else if constexpr (dynamic_task_definition<Definition>) {
1771 base += Definition::count;
1775 template<
auto Entry,
1776 std::size_t Instance,
1777 typename Definition,
1779 [[nodiscard]]
spawn_result start_entry(std::size_t& base)
1781 if constexpr (declared_task_definition<Definition> &&
1782 same_task_entry<Definition::entry, Entry>) {
1783 if constexpr (Instance < Definition::instances) {
1784 return start_definition_instance<Definition>(base + Instance,
1790 if constexpr (declared_task_definition<Definition>) {
1791 base += Definition::instances;
1792 }
else if constexpr (dynamic_task_definition<Definition>) {
1793 base += Definition::count;
1795 if constexpr (
sizeof...(Rest) > 0U) {
1796 return start_entry<
Entry, Instance, Rest...>(base);
1803 template<
auto Entry,
1804 std::size_t Instance,
1805 typename Definition,
1807 [[nodiscard]]
bool find_entry(std::size_t& base, std::size_t& task_id)
const
1809 if constexpr (declared_task_definition<Definition> &&
1810 same_task_entry<Definition::entry, Entry>) {
1811 if constexpr (Instance < Definition::instances) {
1812 task_id = base + Instance;
1818 if constexpr (declared_task_definition<Definition>) {
1819 base += Definition::instances;
1820 }
else if constexpr (dynamic_task_definition<Definition>) {
1821 base += Definition::count;
1823 if constexpr (
sizeof...(Rest) > 0U) {
1824 return find_entry<
Entry, Instance, Rest...>(base, task_id);
1833 std::array<tsm::task_context, task_count> contexts_{};
1834 std::array<tsm::task, task_count> tasks_{};
1835 std::array<std::size_t, task_count> ready_queue_{};
1836 std::array<std::uint8_t, task_count> priorities_{};
1837 timer_queue<task_count> timers_{};
1838 std::size_t ready_push_{};
1839 std::size_t ready_pop_{};
1840 std::size_t ready_size_{};
1842 std::uint32_t timer_sequence_{};
1845 template<
typename Runtime>
1847 coroutine_scheduler<Runtime, typename runtime_task_list_of<Runtime>::type>;
1849 template<
typename Runtime>
1855 template<
typename Runtime,
template<
typename>
typename SchedulerFor>
1856 class basic_executor_task_binding
1859 explicit basic_executor_task_binding(
Runtime& runtime)
1860 : runtime_(&runtime)
1861 , coroutines_(runtime)
1865 [[nodiscard]]
bool step()
1870 if (coroutines_.step()) {
1873 if (runtime_->step()) {
1874 static_cast<void>(coroutines_.poll_waiting());
1877 static_cast<void>(coroutines_.poll_waiting());
1878 return coroutines_.step();
1881 std::size_t run_ready()
1883 std::size_t rounds{};
1892 return coroutines_.tick(elapsed_ticks);
1897 return tick(elapsed_ticks.
count());
1902 coroutines_.start_all();
1905 template<auto Entry, std::
size_t Instance = 0U>
1908 return coroutines_.template start<Entry, Instance>();
1911 template<
auto Entry,
typename... Args>
1914 return coroutines_.template spawn<Entry>(std::forward<Args>(args)...);
1917 template<auto Entry, std::
size_t Instance = 0U>
1920 return coroutines_.template status<Entry, Instance>();
1923 template<auto Entry, std::
size_t Instance = 0U>
1926 return coroutines_.template failure_reason<Entry, Instance>();
1929 template<auto Entry, std::
size_t Instance = 0U>
1930 [[nodiscard]]
bool cancel() noexcept
1932 return coroutines_.template cancel<Entry, Instance>();
1935 void cancel_all() noexcept
1937 coroutines_.cancel_all();
1942 SchedulerFor<Runtime> coroutines_;
1945 template<
typename Runtime>
1947 basic_executor_task_binding<Runtime, coroutine_scheduler_for>;
1949 template<
typename Runtime>
1951 basic_executor_task_binding<Runtime, priority_coroutine_scheduler_for>;
1962 template<std::
size_t Capacity>
1965 template<
typename Runtime>
Definition: coroutine.h:940
bool await_resume() const noexcept
Definition: coroutine.h:959
checked_send_event_awaitable(Runtime &runtime, Event &&event)
Definition: coroutine.h:942
bool await_suspend(task::handle_type)
Definition: coroutine.h:953
bool await_ready() const noexcept
Definition: coroutine.h:948
Definition: coroutine.h:656
constexpr periodic_ticks(tsm::tick_rep period) noexcept
Definition: coroutine.h:658
tsm::tick_rep period() const noexcept
Definition: coroutine.h:673
constexpr periodic_ticks(tick_count period) noexcept
Definition: coroutine.h:663
Definition: coroutine.h:767
bool await_ready() noexcept
Definition: coroutine.h:774
select_awaitable(Awaitables... awaitables)
Definition: coroutine.h:769
select_result await_resume() noexcept
Definition: coroutine.h:785
void await_suspend(task::handle_type handle) noexcept
Definition: coroutine.h:779
Definition: coroutine.h:908
send_event_awaitable(Runtime &runtime, Event &&event)
Definition: coroutine.h:910
bool await_ready() const noexcept
Definition: coroutine.h:916
bool await_suspend(task::handle_type)
Definition: coroutine.h:921
bool await_resume() const noexcept
Definition: coroutine.h:927
Definition: coroutine.h:113
std::size_t used() const noexcept
Definition: coroutine.h:129
std::size_t capacity() const noexcept
Definition: coroutine.h:133
void * allocate(std::size_t bytes, std::size_t alignment) noexcept
Definition: coroutine.h:118
Definition: coroutine.h:196
task_failure_reason failure_reason() const noexcept
Definition: coroutine.h:279
bool ready_to_resume() const noexcept
Definition: coroutine.h:360
void prepare_start() noexcept
Definition: coroutine.h:309
void wait_until(Object const &object, Predicate predicate) noexcept
Definition: coroutine.h:352
bool predicate_ready() const noexcept
Definition: coroutine.h:378
void(*)(void *, std::size_t) noexcept cancel_sleep_fn
Definition: coroutine.h:201
void cancel_sleep() noexcept
Definition: coroutine.h:344
void mark_ready() noexcept
Definition: coroutine.h:293
task_wait_kind wait_kind() const noexcept
Definition: coroutine.h:271
void mark_running() noexcept
Definition: coroutine.h:321
void bind(static_coroutine_arena< Bytes > &arena, std::size_t task_id, std::size_t instance_id, std::size_t frame_limit, void *scheduler, wake_fn wake, sleep_fn sleep, cancel_sleep_fn cancel_sleep) noexcept
Definition: coroutine.h:211
bool(*)(void *, std::size_t, tsm::tick_rep) noexcept sleep_fn
Definition: coroutine.h:200
task_context(static_coroutine_arena< 1U > *, std::size_t, std::size_t, std::size_t)=delete
std::uint32_t generation() const noexcept
Definition: coroutine.h:283
void cancel() noexcept
Definition: coroutine.h:401
std::size_t instance_id() const noexcept
Definition: coroutine.h:263
bool(*)(void const *) noexcept predicate_fn
Definition: coroutine.h:198
std::size_t task_id() const noexcept
Definition: coroutine.h:259
void set_now(tsm::tick_rep now) noexcept
Definition: coroutine.h:288
task_status status() const noexcept
Definition: coroutine.h:275
void(*)(void *, std::size_t) noexcept wake_fn
Definition: coroutine.h:199
void * allocate_frame(std::size_t bytes, std::size_t alignment) noexcept
Definition: coroutine.h:239
tsm::tick_rep now() const noexcept
Definition: coroutine.h:267
void request_wake() noexcept
Definition: coroutine.h:407
void mark_failed(task_failure_reason reason=task_failure_reason::unhandled_exception) noexcept
Definition: coroutine.h:390
void sleep_for(tsm::tick_rep ticks) noexcept
Definition: coroutine.h:331
void mark_completed() noexcept
Definition: coroutine.h:384
void clear_queued() noexcept
Definition: coroutine.h:416
Definition: coroutine.h:43
std::coroutine_handle< promise_type > handle_type
Definition: coroutine.h:46
handle_type handle() const noexcept
Definition: coroutine.h:88
task & operator=(task &&other) noexcept
Definition: coroutine.h:63
task(handle_type handle) noexcept
Definition: coroutine.h:49
~task()
Definition: coroutine.h:73
task(task &&other) noexcept
Definition: coroutine.h:57
bool resume()
Definition: coroutine.h:553
task & operator=(task const &)=delete
task(task const &)=delete
bool done() const noexcept
Definition: coroutine.h:83
Definition: coroutine.h:1004
until_active_awaitable(Machine &machine)
Definition: coroutine.h:1006
bool await_ready() const noexcept
Definition: coroutine.h:1011
void await_suspend(task::handle_type handle) const noexcept
Definition: coroutine.h:1016
void await_resume() const noexcept
Definition: coroutine.h:1025
constexpr std::uint16_t npos
Definition: core_algorithms.h:31
requires(!has_transition_type_c< T > &&has_transition_member_c< T >) struct transitions_of< T >
Definition: transition.h:479
concept awaitable
Definition: io.h:67
task_context * find_task_context() noexcept
Definition: coroutine.h:446
concept dynamic_task_definition
Definition: coroutine.h:1206
consteval std::size_t selected_frame_bytes()
Definition: coroutine.h:1100
concept declared_task_definition
Definition: coroutine.h:1198
consteval std::size_t selected_instances()
Definition: coroutine.h:1080
coroutine_scheduler< Runtime, typename runtime_task_list_of< Runtime >::type > coroutine_scheduler_for
Definition: coroutine.h:1847
consteval std::uint8_t selected_priority()
Definition: coroutine.h:1120
basic_executor_task_binding< Runtime, priority_coroutine_scheduler_for > priority_executor_task_binding
Definition: coroutine.h:1951
basic_executor_task_binding< Runtime, coroutine_scheduler_for > executor_task_binding
Definition: coroutine.h:1947
concept basic_awaitable
Definition: coroutine.h:724
void cancel_awaitable(Awaitable &awaitable, task_context &context) noexcept
Definition: coroutine.h:745
concept same_task_entry
Definition: coroutine.h:1213
coroutine_scheduler< Runtime, typename runtime_task_list_of< Runtime >::type, true > priority_coroutine_scheduler_for
Definition: coroutine.h:1853
detail::runtime_impl< Definition, Policy, MachinePolicy > Runtime
Definition: runtime.h:531
detail::timer_queue< Capacity > timer_queue
Definition: coroutine.h:1963
detail::task_resources< Runtime > task_resources
Definition: coroutine.h:1966
status
Definition: transport.h:47
Definition: bare_metal.h:20
auto send_event(Runtime &runtime, Event &&event)
Definition: coroutine.h:972
task_failure_reason
Definition: coroutine.h:170
runtime::Runtime< Definition, Policy, MachinePolicy > Runtime
Definition: runtime.h:35
constexpr tick_count ticks(tick_rep value) noexcept
Definition: ticks.h:85
sleep_ticks_awaitable after_ticks(tsm::tick_rep ticks) noexcept
Definition: coroutine.h:638
task_wait_kind
Definition: coroutine.h:150
auto until_active(Machine &machine) noexcept
Definition: coroutine.h:1033
sleep_ticks_awaitable sleep_ticks(tsm::tick_rep ticks) noexcept
Definition: coroutine.h:622
auto select(Awaitables &&... awaitables)
Definition: coroutine.h:882
task_status
Definition: coroutine.h:160
auto with_timeout(Awaitable &&awaitable, tsm::tick_rep ticks)
Definition: coroutine.h:893
timeout_ticks_awaitable timeout_ticks(tsm::tick_rep ticks) noexcept
Definition: coroutine.h:710
spawn_result
Definition: coroutine.h:181
yield_awaitable yield() noexcept
Definition: coroutine.h:589
auto try_send_event(Runtime &runtime, Event &&event)
Definition: coroutine.h:987
auto try_send(Runtime &runtime, Args &&... args)
Definition: coroutine.h:997
auto send(Runtime &runtime, Args &&... args)
Definition: coroutine.h:980
TSM_TICK_REP tick_rep
Definition: ticks.h:35
Definition: coroutine.h:1059
static constexpr std::size_t count
Definition: coroutine.h:1062
Definition: coroutine.h:1046
static constexpr std::size_t value
Definition: coroutine.h:1047
Definition: coroutine.h:1040
static constexpr std::size_t value
Definition: coroutine.h:1041
Result of a select wait.
Definition: coroutine.h:756
std::size_t index
Definition: coroutine.h:757
Definition: coroutine.h:603
void await_cancel(task_context &context) const noexcept
Definition: coroutine.h:614
void await_resume() const noexcept
Definition: coroutine.h:618
void await_suspend(task::handle_type handle) const noexcept
Definition: coroutine.h:610
bool await_ready() const noexcept
Definition: coroutine.h:606
tsm::tick_rep ticks
Definition: coroutine.h:604
Definition: coroutine.h:517
void await_resume() const noexcept
Definition: coroutine.h:528
void await_suspend(task::handle_type handle) const noexcept
Definition: coroutine.h:522
bool await_ready() const noexcept
Definition: coroutine.h:518
Definition: coroutine.h:465
final_awaitable final_suspend() noexcept
Definition: coroutine.h:531
void return_void() noexcept
Definition: coroutine.h:535
std::suspend_always initial_suspend() noexcept
Definition: coroutine.h:511
task get_return_object() noexcept
Definition: coroutine.h:506
static task get_return_object_on_allocation_failure() noexcept
Definition: coroutine.h:474
promise_type(First &first, Args &... args) noexcept
Definition: coroutine.h:469
task_context & context() noexcept
Definition: coroutine.h:543
void unhandled_exception() noexcept
Definition: coroutine.h:536
Definition: coroutine.h:1143
static constexpr std::uint8_t priority
Definition: coroutine.h:1151
static constexpr auto entry
Definition: coroutine.h:1146
Definition: coroutine.h:1073
static constexpr std::size_t size
Definition: coroutine.h:1074
Definition: coroutine.h:1052
static constexpr std::uint8_t value
Larger numeric values run first in priority-aware cooperative executors.
Definition: coroutine.h:1054
Definition: coroutine.h:1162
static constexpr std::size_t size
Definition: coroutine.h:1163
Strong value type for semantic scheduler ticks.
Definition: ticks.h:54
constexpr tick_rep count() const noexcept
Definition: ticks.h:73
Definition: coroutine.h:691
void await_cancel(task_context &context) const noexcept
Definition: coroutine.h:702
bool await_ready() const noexcept
Definition: coroutine.h:694
void await_resume() const noexcept
Definition: coroutine.h:706
void await_suspend(task::handle_type handle) const noexcept
Definition: coroutine.h:698
tsm::tick_rep ticks
Definition: coroutine.h:692
Definition: coroutine.h:576
void await_suspend(task::handle_type handle) const noexcept
Definition: coroutine.h:581
void await_resume() const noexcept
Definition: coroutine.h:585
bool await_ready() const noexcept
Definition: coroutine.h:577
Target-neutral tick value type.