rok::core::task
rok::core::task: tasks on the work-stealing executor (stdlib 2.18,
refs-lang 7.6) and block_on (2.20.6); time is task::time.
One executor per process, started on first use: N workers on threads
that live as long as the process (N = online CPUs or ROK_WORKERS),
the blocking lane and the I/O driver. block_on and par::* attach
the calling thread as a guest until their future and its
spawn_local tasks are done. Without threads (wasm32-wasi, the
browser) the guest runs everything itself, waiting in rok_io_wait.
A worker has a local queue (spawn_local, never stolen) and a
Chase-Lev deque; guests have neither and push to the shared injector.
A worker takes from its local queue, its deque, the injector, then
steals; the owner takes FIFO too, since LIFO lets a self-waking task
(yield_now) starve the rest of its deque.
A task's state goes IDLE -> SCHEDULED -> RUNNING -> IDLE / DONE; a wake while RUNNING marks it NOTIFIED and it is queued again after the poll.
Idle workers sleep on a flag; a push wakes one flagged worker, which searches until it finds work, and the last searcher to find a task wakes the next (tokio's scheme). No worker spins before sleeping.
I/O (707): a driver thread blocks in kqueue / epoll and unparks the tasks waiting on a ready fd.
Blocking calls (706 §7.6.7): each pool thread has a runtime lane that
is marked blocked for the length of a blocking call. A monitor scans
the lanes every millisecond; a worker blocked across a whole scan is
handed to a spare or new thread, and the blocked thread finishes its
poll as an orphan guest, then waits as a spare (10 s, then exits).
At most 512 extra threads. A worker with live spawn_local tasks is
never handed on.
Cancellation (2.18.4, 707 §7.7.10): Task::cancel sets a flag and
wakes the task; each await checks it on entry and after each resume
and leaves the body like a return, running finally / using.
Timers: one binary heap behind a Mutex (707 §7.7.5).
ROK_THREAD_PER_CORE=1 (706 §7.6.8) keeps every task on one worker's
local queue, so nothing is stolen. ROK_DYNAMIC_WORKERS=1 (707
§7.7.8) wakes only active workers and activates one more when all are
busy.
REPL sessions are saved between cells (rok_session_hold): every
executor thread is busy from rok_session_enter to
rok_session_leave except while asleep, and parks at
rok_session_pass (between tasks, holding no lock) while a hold is
requested, so no task is mid-poll in a saved session.
Modules
timerok::core::task::time - `Duration` / `Instant` (stdlib spec 2.18.6, 3.3.2).
Structs
TaskRef
pub struct TaskRefA task as the executor sees it (what a Waker holds).
Trait implementations 2
unsafe impl Send for TaskRefunsafe impl Sync for TaskRef
Pool
pub struct PoolThe process's work-stealing executor.
pub const fn workers(self) -> usizeNumber of pool threads.
Trait implementations 2
unsafe impl Send for Poolunsafe impl Sync for Pool
Worker
pub struct WorkerA thread running tasks: a pool thread, or a guest (block_on).
Task
pub struct Task<T>A spawned task; await it for its result (2.18.2).
pub fn is_finished(self) -> boolpub const fn id(self) -> TaskIdThis task's id (what
task::id()returns inside it).pub fn cancel(self)Ask the task to stop (2.18.4): it is woken, its current
awaitleaves the body (running thefinally/usingcleanups on the way out) and it finishes without a result. Awaiting it then panics; usetry await t.join()to seeCancellationError. A task that reaches no cancellation point after the cancel finishes normally, with its result.pub fn is_cancelled(self) -> boolpub const fn join(self) -> Join<T>Await the result, throwing
CancellationErrorfor a cancelled task.
Trait implementations 3
unsafe impl<T: Send> Send for Task<T>impl<T> Future for Task<T>impl<T> Transfer for Task<T>
Join
pub struct Join<T>Task::join.
pub fn poll(ref self, ref ctx: Context) throws (CancellationError) -> Poll<T>
TaskId
pub struct TaskIdIdentifies a task for as long as the process runs (ids are never
reused): Task::id, task::id(). Not in spec 2.18 (tokio's
task::Id).
pub const fn as_u64(self) -> u64
Trait implementations 5
impl PartialEq for TaskIdimpl Eq for TaskIdimpl Hash for TaskIdimpl Display for TaskIdimpl Debug for TaskId
CancellationError
pub struct CancellationErrorA task was cancelled (2.18.4).
Trait implementations 3
impl Display for CancellationErrorimpl Debug for CancellationErrorimpl Error for CancellationError
SelectFuture
pub struct SelectFuture<F>Trait implementations 1
impl<F: Future> Future for SelectFuture<F>
TimeoutError
pub struct TimeoutErrortask::timeout ran out.
Trait implementations 3
impl Display for TimeoutErrorimpl Debug for TimeoutErrorimpl Error for TimeoutError
IoReady
pub struct IoReadyTrait implementations 1
impl Future for IoReady
Blocking
pub struct Blocking<T>Trait implementations 1
impl<T> Future for Blocking<T>
Functions
wake_task
pub fn wake_task(t: TaskRef)Schedule t to be polled (Waker::wake); safe from any thread.
cancel_requested
pub fn cancel_requested(ctx: Context) -> boolIs the task polling with ctx cancelled? (The compiler's await
checks this: 2.18.4 cancellation points.) A true answer means the
caller leaves: the cancelled task (or select proxy) is marked
unwinding.
unwinding
pub fn unwinding(ctx: Context) -> boolWhether a future that just returned Ready with ctx may have left
because of a cancel (its value is then a placeholder): the await
after a ready poll checks this, not the bare flag, so a value a
hand-written future handed over (a message, a guard) is kept when the
cancel lands meanwhile - the next cancellation point leaves.
block_on
pub fn block_on<F: Future>(fut: F) -> F::OutputRun fut to completion from synchronous code (2.20.6). It returns
once the spawn_local tasks pinned to this thread are done too.
block_on_try
pub fn block_on_try<Tblock_on for a throwing async body: its error is thrown here.
host_enter
pub fn host_enter()This thread works as the host loop's guest worker (host_leave
ends it): tasks spawned with spawn_local belong to that worker.
host_leave
pub fn host_leave()host_run
pub fn host_run(slice: fn() -> i64) -> boolOne turn of the host's loop (inside host_enter): every runnable
task and due timer, until none is left; then the wait for sockets and
timers, at most slice() ns (< 0: until nothing is left to wait for;
0: none), and what it woke. Whether a socket or timer still waits.
workers
pub fn workers() -> usizeWorkers of the executor this thread runs tasks on (1 outside one, and without threads, where the one thread runs every task).
cpu_count
pub fn cpu_count() -> usizeOnline CPUs: the executor's pool threads.
id
pub fn id() -> TaskIdThe running task's id; panics outside a task (try_id).
try_id
pub fn try_id() -> TaskId | noneThe running task's id, or none outside a task (sync code, a
spawn_blocking thread).
spawn
pub fn spawn<F: Future + Send>(fut: F) -> Task<F::Output> where F::Output: SendRun fut as a new task on any worker, concurrently with the
spawner (2.18.1). Needs a running executor (inside async fn main /
block_on). The task gets its own copy of every collection fut
holds, what its coroutine captured included (2.13.9): the spawner
keeps the originals.
spawn_local
pub fn spawn_local<F: Future>(fut: F) -> Task<F::Output>Run fut as a new task on this worker only (it need not be Send).
From a task a block_on thread happens to poll, that is one pool
worker, and the task starts once that poll ends.
join
pub async fn join<T>(tasks: List<Task<T>>) -> List<T>Every task's result, in order (2.18.1).
race
pub async fn race<T>(tasks: List<Task<T>>) -> TThe result of whichever task finishes first (2.18.1).
select
pub const fn select<F: Future>(futs: List<F>) -> SelectFuture<F>The first of futs to complete, with its index: let (i, v) = await task::select([a, b]) (refs-lang 4.12.9 names select; 2.18 gives no
signature). Unlike race the futures are not spawned: they run inside
the awaiting task, polled in list order (ties go to the lower index).
The futures share one type: async { .. } blocks with the same
output do (wrap differing outputs, async { Msg::A(await a) }).
Once one completes, every other one that has started is polled once
more as cancelled (its await leaves through finally / using, as
for Task::cancel) and dropped. Panics on an empty list.
sleep
pub async fn sleep(dur: Duration)Completes once dur has passed since its first poll (2.18.1).
sleep_until
pub async fn sleep_until(when: Instant)Completes at when.
yield_now
pub async fn yield_now()Let the other ready tasks run once (2.18.1).
timeout
pub async fn timeout<T>(dur: Duration, task: Task<T>) throws (TimeoutError) -> Ttask's result, or TimeoutError once dur has passed since the
first poll (2.18.1): try await task::timeout(d, t).
park
pub fn park(key: usize, waker: Waker)Wake waker at the next unpark(key). The entry goes at that
unpark or when the waker's task finishes (a cancelled task's wait).
registrations
pub fn registrations() -> usizeParked wakers (all keys) plus pending timers of unfinished tasks: a diagnostic (a cancelled task leaves none behind).
unpark
pub fn unpark(key: usize)Wake every task parked on key (cheap when no task ever parked).
wake_io
pub fn wake_io(fd: i32)Wake every task waiting on fd's readiness: after a shutdown or
a close, which may raise no poller event (stdlib 2.18.1).
readable
pub const fn readable(fd: i32) -> IoReadyCompletes once fd may be readable (await task::readable(fd)
after a read hit WouldBlock); it may also complete spuriously, so
retry the operation in a loop.
writable
pub const fn writable(fd: i32) -> IoReadyreadable for writes.
spawn_blocking
pub fn spawn_blocking<T: Send>(f: fn() -> T + Send) -> Blocking<T>Run f on the executor's blocking lane; the future completes with
its result (tokio's spawn_blocking). For syscalls with no readiness
to wait on, like regular files under kqueue / epoll. f is queued at
once; a cancelled awaiter leaves it to finish in the background and
its result is dropped.
Implementations
impl Timeout
pub fn poll(ref self, ref ctx: Context) throws (TimeoutError) -> Poll<T>