executor
import std::future::executor; · source
Executor
type struct Executor {
inner: ExecInner*;
worker_tids: u64[];
static new() -> Executor;
static with_threads(n: u32) -> Executor;
static with_threads_and_blocking(n: u32, blocking: u32) -> Executor;
spawn<F, O>(mut &this, fut: F) -> JoinHandle<O>
where F: Future<O>;
spawn_detached<F, O>(mut &this, fut: F) -> void
where F: Future<O>;
block_on<F, O>(mut &this, root: F) -> O
where F: Future<O>;
}
An Executor owns a queue of ready tasks and a pool of worker threads that drive them, plus the reactor and blocking pool those tasks park on.
import std::future;
mut ex: Executor = Executor::new();
const result: Report = ex.block_on(run_pipeline(config));
| Method | Notes |
|---|---|
new() | Sizes the worker pool to the hardware thread count. |
with_threads(n) | Pick the worker count yourself. |
with_threads_and_blocking(n, blocking) | Also cap the blocking pool — the threads that run getaddrinfo, file I/O, and child waits off the executor. |
spawn(fut) | JoinHandle<O>; workers begin driving it immediately. |
spawn_detached(fut) | Fire and forget. |
block_on(root) | Spawns root and blocks the calling thread until it finishes. |
join and block_on never poll on the calling thread — the workers own all polling.
JoinHandle<O>
type struct JoinHandle<O> {
shared: TaskShared<O>*;
exec: ExecInner*;
join(mut this) -> Result<O, JoinError>;
detach(mut this) -> void;
abort(&this) -> void;
is_finished(&this) -> boolean;
}
Dropping a handle without joining or detaching detaches it: the task runs on and its result is discarded. abort() requests cancellation, and the task is reclaimed — its output never produced — the next time a worker reaches it; a join on an aborted task returns Err(Cancelled).
JoinError
type enum JoinError {
Cancelled;
Panicked(PanicInfo);
}
Cancelled is what join returns on an aborted task; Panicked carries the panic's message and location, and only occurs under --panic=unwind.
Dropping the Executor signals shutdown, joins the workers, then reclaims any still-queued tasks.
Concurrent-poll safety
With two or more workers a task can be woken — by itself mid-poll, or later by another thread — while a worker is already polling it. Polling one future from two workers at once is a data race, so each task carries an atomic run state (IDLE, SCHEDULED, RUNNING, NOTIFIED) that guarantees a task is enqueued at most once and polled by at most one worker.
wake() moves IDLE → SCHEDULED and enqueues, or RUNNING → NOTIFIED and defers to the running worker. A worker moves SCHEDULED → RUNNING to poll, then RUNNING → IDLE on a quiet Pending, or re-schedules on NOTIFIED.
Task isolation
Under --panic=unwind the poll boundary runs inside a catch: a panicking task is caught, finishes as panicked, and its join returns Err(Panicked(info)) — its siblings keep running.
Under the default --panic=abort the catch machinery is a compile error, so the boundary is a plain direct call and a task panic aborts the whole process. That is the accepted degradation; see catch_unwind.
Trait implementations
implement trait Drop for struct Executor
implement<O> trait Drop for struct JoinHandle<O>