blob: 2894cd186e49656a2077a8b91331206a3be61e5a [file] [log] [blame]
Stjepan Glavina1479e862019-08-12 20:18:51 +02001//! Task abstraction for building executors.
2//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +02003//! To spawn a future onto an executor, we first need to allocate it on the heap and keep some
4//! state alongside it. The state indicates whether the future is ready for polling, waiting to be
5//! woken up, or completed. Such a future is called a *task*.
Stjepan Glavina1479e862019-08-12 20:18:51 +02006//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +02007//! This crate helps with task allocation and polling its future to completion.
Stjepan Glavina1479e862019-08-12 20:18:51 +02008//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +02009//! # Spawning
Stjepan Glavina1479e862019-08-12 20:18:51 +020010//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020011//! All executors have some kind of queue that holds runnable tasks:
Stjepan Glavina1479e862019-08-12 20:18:51 +020012//!
13//! ```
14//! # #![feature(async_await)]
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020015//! #
16//! let (sender, receiver) = crossbeam::channel::unbounded();
17//! #
18//! # // A future that will get spawned.
19//! # let future = async { 1 + 2 };
20//! #
21//! # // A function that schedules the task when it gets woken up.
22//! # let schedule = move |task| sender.send(task).unwrap();
23//! #
24//! # // Construct a task.
25//! # let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020026//! ```
27//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020028//! A task is constructed using the [`spawn`] function:
Stjepan Glavina1479e862019-08-12 20:18:51 +020029//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020030//! ```
31//! # #![feature(async_await)]
32//! #
33//! # let (sender, receiver) = crossbeam::channel::unbounded();
34//! #
35//! // A future that will be spawned.
36//! let future = async { 1 + 2 };
Stjepan Glavina1479e862019-08-12 20:18:51 +020037//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020038//! // A function that schedules the task when it gets woken up.
39//! let schedule = move |task| sender.send(task).unwrap();
Stjepan Glavina1479e862019-08-12 20:18:51 +020040//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020041//! // Construct a task.
42//! let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020043//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020044//! // Push the task into the queue by invoking its schedule function.
45//! task.schedule();
46//! ```
Stjepan Glavina1479e862019-08-12 20:18:51 +020047//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020048//! The last argument to the [`spawn`] function is a *tag*, an arbitrary piece of data associated
49//! with the task. In most executors, this is typically a task identifier or task-local storage.
Stjepan Glavina1479e862019-08-12 20:18:51 +020050//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020051//! The function returns a runnable [`Task`] and a [`JoinHandle`] that can await the result.
Stjepan Glavina1479e862019-08-12 20:18:51 +020052//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020053//! # Execution
54//!
55//! Task executors have some kind of main loop that drives tasks to completion. That means taking
56//! runnable tasks out of the queue and running each one in order:
57//!
58//! ```no_run
59//! # #![feature(async_await)]
60//! #
61//! # let (sender, receiver) = crossbeam::channel::unbounded();
62//! #
63//! # // A future that will get spawned.
64//! # let future = async { 1 + 2 };
65//! #
66//! # // A function that schedules the task when it gets woken up.
67//! # let schedule = move |task| sender.send(task).unwrap();
68//! #
69//! # // Construct a task.
70//! # let (task, handle) = async_task::spawn(future, schedule, ());
71//! #
72//! # // Push the task into the queue by invoking its schedule function.
73//! # task.schedule();
74//! #
75//! for task in receiver {
76//! task.run();
77//! }
78//! ```
79//!
80//! When a task is run, its future gets polled. If polling does not complete the task, that means
81//! it's waiting for another future and needs to go to sleep. When woken up, its schedule function
82//! will be invoked, pushing it back into the queue so that it can be run again.
Stjepan Glavina1479e862019-08-12 20:18:51 +020083//!
84//! # Cancellation
85//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020086//! Both [`Task`] and [`JoinHandle`] have a method that cancels the task. When cancelled, the
87//! task's future will not be polled again and will get dropped instead.
88//!
89//! If cancelled by the [`Task`] instance, the task is destroyed immediately. If cancelled by the
90//! [`JoinHandle`] instance, it will be scheduled one more time and the next attempt to run it will
91//! simply destroy it.
Stjepan Glavina1479e862019-08-12 20:18:51 +020092//!
93//! # Performance
94//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020095//! Task construction incurs a single allocation only that holds its state, the schedule function,
96//! and the future or the result of the future if completed.
Stjepan Glavina1479e862019-08-12 20:18:51 +020097//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020098//! The layout of a task is equivalent to 4 words followed by the schedule function, and then by a
99//! union of the future and its output.
Stjepan Glavina1479e862019-08-12 20:18:51 +0200100//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200101//! [`spawn`]: fn.spawn.html
Stjepan Glavina1479e862019-08-12 20:18:51 +0200102//! [`Task`]: struct.Task.html
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200103//! [`JoinHandle`]: struct.JoinHandle.html
Stjepan Glavina1479e862019-08-12 20:18:51 +0200104
105#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200106#![doc(test(attr(deny(rust_2018_idioms, warnings))))]
107#![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
Stjepan Glavina1479e862019-08-12 20:18:51 +0200108
109mod header;
110mod join_handle;
111mod raw;
112mod state;
113mod task;
114mod utils;
115
116pub use crate::join_handle::JoinHandle;
117pub use crate::task::{spawn, Task};