|
tin
1.5.9
|
Coroutines are the tin task model for deterministic cooperative workflows. They run beside HSM runtimes, channels, actors, and platform adapters without creating framework-owned threads, heap-backed task frames, or callback registration.
Use coroutine tasks when a system needs workflow code that waits, sleeps, retries, samples, supervises, or sequences typed events:
An HSM still owns legal product behavior. A coroutine task owns cooperative workflow around that behavior.
tsm::task for the coroutine return type.tsm::task_context for per-task runtime state.tsm::tasks<...> for the task list declared by a machine definition.tsm::task_def<Entry, Options...> for a statically declared task entry.tsm::dynamic_task_slots<N, tsm::frame_bytes<Bytes>> for caller-spawned static task slots.tsm::frame_bytes<N> for explicit coroutine-frame storage.tsm::task_priority<N> for priority cooperative executors.tsm::task_group<Entries...> for supervised start/cancel groups.tsm::cooperative_executor and tsm::priority_cooperative_executor for caller-owned task and runtime execution.tsm::after_ticks(n), tsm::yield(), and tsm::send<Event>(runtime) for common awaitable operations.tsm::select(...), tsm::timeout_ticks(n), and tsm::every_ticks{n} for multi-way waits, bounded waits, and periodic task loops.tsm::event_flag, tsm::signal<T>, tsm::channel<T, N>, tsm::mutex<T>, and tsm::cancellation_source for cooperative synchronization.Coroutine tasks do not run on their own. An executor resumes ready tasks when the application gives the executor a turn:
run_ready() drains currently ready work. tick() advances task sleeps and delayed runtime events by explicit tick counts. A Linux thread, RTOS task, bare-metal superloop, simulator loop, or unit test can own this execution context.
A task entry is a callable object whose operator() returns tsm::task. Machine definitions declare entries in using tasks = ... so task storage is visible in the type.
The frame budget is part of the declaration. A coroutine frame that exceeds the budget reports a failure.
Runtime synchronization primitives wake coroutine tasks through the executor ready queue. They do not block an OS thread.
Typical wait surfaces:
event_flag wait awaitables for level-triggered task wakeups;signal<T> wait awaitables for latest-value notifications;channel<T, N> receive awaitables for bounded FIFO handoff;mutex<T> lock awaitables for cooperative payload protection;cancellation_token wait awaitables for supervised shutdown.Interrupt and platform adapters should wake these primitives with the *_from_isr() or notify-style methods where available, then let the executor resume tasks in normal cooperative order.
select lets a task wait for the first of several cooperative operations. This is useful for driver service loops that need either an interrupt, a timeout, or a cancellation signal.
The losing wait branch is cancelled before the task resumes. That keeps waiter lists bounded and prevents stale wakeups from resuming a task later.
Coroutine time is explicit tick time. The runtime does not read a wall clock.
Use tsm::every_ticks when a task should wake on a fixed logical period:
Host clocks, RTOS ticks, hardware timers, and simulation time are adapters that produce elapsed tsm::tick_count values. The same task can run in a unit test, bare-metal superloop, or target executor when the adapter advances ticks deterministically.
Declared tasks auto-start when the executor is constructed unless a task entry is configured for explicit start. A single-runtime executor can start, cancel, and inspect a declared task by entry identity:
Dynamic static slots use the same executor and report the same tsm::spawn_result, tsm::task_status, and tsm::task_failure_reason vocabulary as declared tasks.
Some systems need task entries chosen at runtime while still avoiding heap allocation. Reserve static dynamic slots in the machine definition:
The executor reports spawn_result::no_slot, frame_too_large, or allocation_failed when a dynamic task cannot start.
Task groups give application shells a typed way to supervise related entries:
For cooperative shutdown inside a task, pass a tsm::cancellation_token or shared cancellation source through the task arguments and have the task observe it at explicit wait points.
Task frames, task count, timer slots, and queue slots are included in runtime resource summaries:
This keeps coroutine workflows reviewable for embedded profiles. A resource contract can reject a runtime configuration at compile time if a task frame, timer slot count, or queue budget exceeds the target profile.
Use coroutines for sequential cooperative workflows that benefit from co_await:
Use actors when several components need a common stepping surface and explicit typed links. Use HSM transitions for legal product behavior. These surfaces compose: an actor can wrap an HSM runtime, a coroutine task can feed the runtime, and an actor group can step the assembled system.
Related pages: