Module async::executor
async: tasks, JoinHandle, the local executor
An executor polls futures to completion. Each top-level future it runs is a task: an AsyncTask<F, T> holding the future, its output slot and the bookkeeping the executor and the task's wakers share. Tasks live in memory the caller provides (a static, a local of main, a field of a longer-lived struct, or heap memory you manage) — std/async never allocates — and must stay put from spawn() until they finish (or are aborted and their executor has seen it).
static struct AsyncTask<struct Fetch, int> t1; // any storage that outlives the run
struct LocalExecutor ex = LocalExecutor::new();
t1 = AsyncTask::new(Fetch::new());
struct JoinHandle<int> h = ex.spawn(&t1);
struct VirtualClock clk = VirtualClock::new(0LL);
ex.run(&clk); // until every task is done
match (t1.take()) { case some(v): ...; case none: ... }
LocalExecutor is single-threaded and deterministic: tasks are polled in spawn order, each one once per wake-up, and it has no heap, no locks and no OS dependency — it builds for bare metal and wasm32 as well as hosted targets. Its wakers are safe to call from another thread or an interrupt handler: a wake is two atomic stores (the task's NOTIFIED bit and the executor's 'notified' flag), plus Park::unpark() to cut a park short. What it does while nothing is runnable is up to its Park source:
trait Park { now_ms(); park(timeout_ms); unpark(); }
VirtualClock a clock that jumps straight to the next timer deadline
instead of waiting (tokio's paused time): deterministic
tests and simulations, any target.
FnPark your own clock and idle functions (a SysTick counter and
WFI on bare metal, say).
HostPark the OS monotonic clock, parking on a condition variable
(std/async/host.h; hosted).
IoDriver epoll/kqueue/WSAPoll readiness plus the OS clock
(std/async/net.h; hosted).
For hosted programs that just want a result, std/async/host.h's block_on(&fut) wraps all of this. The multi-threaded executor is std/async/pool.h's ThreadPool; its tasks and JoinHandles are the same types.
Structs
| TaskHeader | The part of an AsyncTask an executor sees. First field of every AsyncTask, so a ?&TaskHeader and the task have the same address: poll_ and drop_ are AsyncTask<F, T>'s own functions, stored by AsyncTask::new as functions of the header (see std/erased.h). |
| AsyncTask | A future and the room for its output: the unit an executor runs. |
| JoinHandle | What spawn() returns: await it (it is a future) or ask it about the task. Ready(some(v)) once the task finished with v, Ready(null) if it was aborted. Copies refer to the same task; only one may be awaited at a time. |
| LocalExecutor | The single-threaded, no-heap executor (see the top of this file). |
| VirtualClock | Simulated time: park(t) moves the clock forward by t instead of waiting, so a run takes no real time and is fully deterministic. park(-1) — every task waits and no timer is pending — is a deadlock in a program that has no other threads or interrupts, and panics. |
| FnPark | A Park from functions: now() for the clock, idle(timeout_ms) to wait (WFI on bare metal; timeout -1 = until an interrupt), wake() (or null) from another context to end idle() early. |
Traits
| Park | A source of time and of waiting, for executors (see above). |
Functions
| async_spawn | Spawn 'task' on the executor that is polling 'cx' — from inside a task (tokio::spawn). Panics if that context has no executor. |
Macros
| ASYNC_TASK_NOTIFIED | TaskHeader::state bits |
| ASYNC_TASK_RUNNING | being polled right now |
| ASYNC_TASK_DONE | finished (output stored) or aborted (dropped) |
| ASYNC_TASK_ABORTED | JoinHandle::abort() was called |
| ASYNC_TASK_QUEUED | in a ThreadPool's run queue |
| ASYNC_TASK_TAKEN | the output was taken (take() or the JoinHandle) |