std1.0.0-beta-7 SafeC docs

Module async::executor

#include <std/async/executor.h> source

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

TaskHeaderThe 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).
AsyncTaskA future and the room for its output: the unit an executor runs.
JoinHandleWhat 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.
LocalExecutorThe single-threaded, no-heap executor (see the top of this file).
VirtualClockSimulated 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.
FnParkA 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

ParkA source of time and of waiting, for executors (see above).

Functions

async_spawnSpawn 'task' on the executor that is polling 'cx' — from inside a task (tokio::spawn). Panics if that context has no executor.

Macros

ASYNC_TASK_NOTIFIEDTaskHeader::state bits
ASYNC_TASK_RUNNINGbeing polled right now
ASYNC_TASK_DONEfinished (output stored) or aborted (dropped)
ASYNC_TASK_ABORTEDJoinHandle::abort() was called
ASYNC_TASK_QUEUEDin a ThreadPool's run queue
ASYNC_TASK_TAKENthe output was taken (take() or the JoinHandle)