21 #include <type_traits>
24 #ifndef TSM_SUPPRESS_AUTO_PLATFORM_ADAPTERS
25 #define TSM_SUPPRESS_AUTO_PLATFORM_ADAPTERS
26 #define TSM_RESTORE_AUTO_PLATFORM_ADAPTERS
29 #ifdef TSM_RESTORE_AUTO_PLATFORM_ADAPTERS
30 #undef TSM_SUPPRESS_AUTO_PLATFORM_ADAPTERS
31 #undef TSM_RESTORE_AUTO_PLATFORM_ADAPTERS
45 template<
typename Work>
46 decltype(
auto)
post(Work&& work)
48 return std::forward<Work>(work)();
67 template<
typename... Runtimes>
72 : runtimes_(&runtimes...)
80 [&progressed](
auto*... runtime) {
81 ((progressed = runtime->step() || progressed), ...);
96 [[nodiscard]]
bool empty()
const
98 bool all_empty{
true };
100 [&all_empty](
auto const*... runtime) {
101 ((all_empty = all_empty && runtime->empty()), ...);
109 std::size_t pending{};
111 [&pending](
auto const*... runtime) {
112 ((pending += runtime->pending_events()), ...);
119 std::tuple<Runtimes*...> runtimes_;
122 template<
typename... Runtimes>
130 template<
typename Executor>
135 : executor_(&executor)
139 template<
auto Entry,
typename... Args>
142 return executor_->template spawn<Entry>(std::forward<Args>(args)...);
146 Executor* executor_{};
149 template<
typename Executor>
152 template<
template<
typename>
typename Binding,
typename... Tasks>
165 [&progressed](
auto&...
task) {
166 ((progressed =
task.step() || progressed), ...);
174 std::size_t rounds{};
183 std::size_t resumed{};
185 [&resumed, elapsed_ticks](
auto&...
task) {
186 ((resumed +=
task.tick(elapsed_ticks)), ...);
201 std::apply([](
auto&...
task) { (
task.start_all(), ...); }, tasks_);
204 template<auto Entry, std::
size_t Instance = 0U>
207 static_assert(
sizeof...(Tasks) == 1U,
208 "tsm: start<Entry, Instance>() is available on a "
209 "single-runtime executor");
210 return std::get<0>(tasks_).template start<Entry, Instance>();
213 template<
auto... Entries>
216 static_assert(
sizeof...(Tasks) == 1U,
217 "tsm: start_group(...) is available on a "
218 "single-runtime executor");
219 (
static_cast<void>(start<Entries>()), ...);
222 template<
auto Entry,
typename... Args>
225 static_assert(
sizeof...(Tasks) == 1U,
226 "tsm: spawn<Entry>() is available on a "
227 "single-runtime executor");
230 return std::get<0>(tasks_).template spawn<Entry>(
231 std::forward<Args>(args)...);
239 template<auto Entry, std::
size_t Instance = 0U>
242 static_assert(
sizeof...(Tasks) == 1U,
243 "tsm: task_status<Entry, Instance>() is available on a "
244 "single-runtime executor");
248 template<auto Entry, std::
size_t Instance = 0U>
251 static_assert(
sizeof...(Tasks) == 1U,
252 "tsm: task_failure_reason<Entry, Instance>() is "
253 "available on a single-runtime executor");
254 return std::get<0>(tasks_)
258 template<auto Entry, std::
size_t Instance = 0U>
261 static_assert(
sizeof...(Tasks) == 1U,
262 "tsm: cancel<Entry, Instance>() is available on a "
263 "single-runtime executor");
264 return std::get<0>(tasks_).template cancel<Entry, Instance>();
267 template<
auto... Entries>
270 static_assert(
sizeof...(Tasks) == 1U,
271 "tsm: cancel_group(...) is available on a "
272 "single-runtime executor");
273 (
static_cast<void>(cancel<Entries>()), ...);
278 std::apply([](
auto&...
task) { (
task.cancel_all(), ...); }, tasks_);
282 std::tuple<Binding<Tasks>...> tasks_;
291 template<
typename... Tasks>
302 template<
typename... Tasks>
311 template<
typename... Tasks>
324 template<
typename... Tasks>
336 template<
typename TickSource,
typename Executor,
typename DelayedEvents>
340 DelayedEvents& delayed_events)
343 if (elapsed_ticks.count() == 0U) {
347 static_cast<void>(executor.tick(elapsed_ticks));
348 static_cast<void>(delayed_events.tick(elapsed_ticks));
349 static_cast<void>(executor.run_ready());
350 return elapsed_ticks.count();
359 template<
typename Runtime, std::
size_t Capacity = 16U>
367 static_assert(Capacity > 0U,
368 "tsm: tick_executor requires at least one timer slot");
375 template<
typename Event>
380 return schedule(std::forward<Event>(event),
ticks, 0U,
false);
383 template<
typename Event>
391 template<
typename Event>
397 schedule(std::forward<Event>(event),
period,
period,
true);
400 template<
typename Event>
412 while (remaining_elapsed > 0U) {
413 const tsm::tick_rep tick_step = next_step(remaining_elapsed);
415 remaining_elapsed -= tick_step;
437 return static_cast<std::size_t
>(
438 std::count_if(timers_.begin(), timers_.end(), [](
auto const& timer) {
450 std::fill(timers_.begin(), timers_.end(), timer_slot{});
454 class scheduled_event
457 static constexpr std::size_t storage_size =
459 static constexpr std::size_t storage_alignment =
462 scheduled_event() =
default;
463 scheduled_event(scheduled_event
const& other)
467 scheduled_event(scheduled_event&& other) noexcept
472 scheduled_event& operator=(scheduled_event
const& other)
474 if (
this != &other) {
482 scheduled_event& operator=(scheduled_event&& other) noexcept
484 if (
this != &other) {
497 template<
typename Event>
500 scheduled_event>) explicit scheduled_event(Event&& event)
502 emplace<std::decay_t<Event>>(std::forward<Event>(event));
505 [[nodiscard]]
bool empty()
const
507 return send_ ==
nullptr;
512 if (send_ ==
nullptr) {
515 return send_(runtime, data());
519 using send_fn = bool (*)(
Runtime&,
void*);
520 using copy_fn = void (*)(
void*,
void const*);
521 using move_fn = void (*)(
void*,
void*);
522 using destroy_fn = void (*)(
void*);
524 template<
typename Event,
typename... Args>
525 void emplace(Args&&... args)
527 static_assert(
sizeof(Event) <= storage_size);
528 static_assert(
alignof(Event) <= storage_alignment);
529 new (data())
Event(std::forward<Args>(args)...);
530 send_ = [](
Runtime& runtime,
void* storage) ->
bool {
531 return runtime.send_event(*
static_cast<Event*
>(storage));
533 copy_ = [](
void* destination,
void const* source) {
534 new (destination)
Event(*
static_cast<Event const*
>(source));
536 move_ = [](
void* destination,
void* source) {
538 Event(std::move(*
static_cast<Event*
>(source)));
540 destroy_ = [](
void* storage) {
545 void copy_from(scheduled_event
const& other)
547 if (other.copy_ ==
nullptr) {
550 other.copy_(data(), other.data());
554 destroy_ = other.destroy_;
557 void move_from(scheduled_event& other)
559 if (other.move_ ==
nullptr) {
562 other.move_(data(), other.data());
566 destroy_ = other.destroy_;
572 if (destroy_ !=
nullptr) {
583 return storage_.data();
585 void const* data()
const
587 return storage_.data();
591 storage_alignment) std::array<unsigned char, storage_size> storage_{};
595 destroy_fn destroy_{};
600 scheduled_event
event{};
607 template<
typename Event>
608 [[nodiscard]]
bool schedule(Event&& event,
614 std::find_if(timers_.begin(), timers_.end(), [](
auto const& timer) {
615 return !timer.active;
617 if (slot != timers_.end()) {
618 slot->event = scheduled_event(std::forward<Event>(event));
619 slot->remaining =
ticks;
621 slot->periodic = periodic;
631 for (
auto const& timer : timers_) {
635 if (timer.remaining == 0U) {
638 if (timer.remaining < tick_step) {
639 tick_step = timer.remaining;
647 for (
auto& timer : timers_) {
651 if (timer.remaining >
ticks) {
652 timer.remaining -=
ticks;
654 timer.remaining = 0U;
659 std::size_t send_due()
662 for (
auto& timer : timers_) {
663 if (!timer.active || timer.remaining != 0U) {
667 if (timer.periodic) {
668 auto event = timer.event;
669 (void)event.send(*runtime_);
670 timer.remaining = timer.period;
672 (void)timer.event.send(*runtime_);
673 timer = timer_slot{};
680 std::array<timer_slot, Capacity> timers_{};
683 template<
typename Runtime>
686 template<
typename Runtime, std::
size_t Capacity = 16U>
Definition: executor.h:154
task_spawner< basic_cooperative_executor > spawner()
Definition: executor.h:234
spawn_result start()
Definition: executor.h:205
void start_group(tsm::task_group< Entries... >)
Definition: executor.h:214
spawn_result spawn(Args &&... args)
Definition: executor.h:223
task_status task_status() const
Definition: executor.h:240
constexpr basic_cooperative_executor(Tasks &... tasks)
Definition: executor.h:156
void start_all()
Definition: executor.h:197
bool step()
Definition: executor.h:161
void cancel_group(tsm::task_group< Entries... >) noexcept
Definition: executor.h:268
bool cancel() noexcept
Definition: executor.h:259
std::size_t tick(tsm::tick_rep elapsed_ticks=1U)
Definition: executor.h:181
void cancel_all() noexcept
Definition: executor.h:276
task_failure_reason task_failure_reason() const
Definition: executor.h:249
std::size_t run_ready()
Definition: executor.h:172
std::size_t tick(tsm::tick_count elapsed_ticks)
Definition: executor.h:192
Definition: executor.h:294
Definition: executor.h:315
Definition: executor.h:69
bool empty() const
Definition: executor.h:96
std::size_t run_ready()
Definition: executor.h:87
std::size_t pending_events() const
Definition: executor.h:107
constexpr runtime_group(Runtimes &... runtimes)
Definition: executor.h:71
bool step()
Definition: executor.h:76
Definition: executor.h:132
spawn_result spawn(Args &&... args)
Definition: executor.h:140
constexpr task_spawner(Executor &executor)
Definition: executor.h:134
Definition: executor.h:361
std::size_t pending() const
Definition: executor.h:435
std::size_t run_ready()
Definition: executor.h:430
tsm::detail::as_type_list_t< events > event_list
Definition: executor.h:365
std::size_t tick(tsm::tick_rep elapsed_ticks=1U)
Definition: executor.h:408
Runtime runtime_type
Definition: executor.h:363
requires(tsm::detail::contains_type< std::decay_t< Event >>(tsm::detail::as_type_list_t< events >{})) bool every_ticks(Event &&event
typename Runtime::events events
Definition: executor.h:364
std::size_t tick(tsm::tick_count elapsed_ticks)
Definition: executor.h:421
bool step()
Definition: executor.h:426
tsm::tick_rep ticks
Definition: executor.h:379
tsm::tick_rep period
Definition: executor.h:395
void clear()
Definition: executor.h:448
requires(tsm::detail::contains_type< std::decay_t< Event >>(tsm::detail::as_type_list_t< events >{})) bool after_ticks(Event &&event
constexpr tick_executor(Runtime &runtime)
Definition: executor.h:370
bool empty() const
Definition: executor.h:443
Definition: coroutine.h:43
Concepts for runtime queues and dispatch policies.
Static coroutine tasks for tsm runtime executors.
consteval std::size_t max_alignof(type_list< T, Ts... >)
Definition: type_list.h:146
typename as_type_list< T >::type as_type_list_t
Definition: type_list.h:175
consteval std::size_t max_sizeof(type_list< T, Ts... >)
Definition: type_list.h:134
consteval bool contains_type(type_list< Ts... >)
Definition: type_list.h:124
concept tick_source
Definition: io.h:243
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
Definition: freertos.h:26
detail::runtime_impl< Definition, Policy, MachinePolicy > Runtime
Definition: runtime.h:531
tick_executor(Runtime &) -> tick_executor< Runtime >
priority_cooperative_executor(Tasks &...) -> priority_cooperative_executor< Tasks... >
tsm::tick_rep drive_elapsed_ticks(TickSource &tick_source, Executor &executor, DelayedEvents &delayed_events)
Definition: executor.h:338
cooperative_executor(Tasks &...) -> cooperative_executor< Tasks... >
runtime_group(Runtimes &...) -> runtime_group< Runtimes... >
task_failure_reason
Definition: coroutine.h:170
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
periodic_ticks every_ticks
Definition: coroutine.h:682
task_status
Definition: coroutine.h:160
spawn_result
Definition: coroutine.h:181
auto send(Runtime &runtime, Args &&... args)
Definition: coroutine.h:980
TSM_TICK_REP tick_rep
Definition: ticks.h:35
Definition: executor.h:44
bool step()
Definition: executor.h:51
decltype(auto) post(Work &&work)
Definition: executor.h:46
std::size_t run_ready()
Definition: executor.h:55
Definition: coroutine.h:1073
Definition: coroutine.h:1162
Strong value type for semantic scheduler ticks.
Definition: ticks.h:54
constexpr tick_rep count() const noexcept
Definition: ticks.h:73