blob: 153cb438f8c95cfa9a56352e4122bc8b2aa311d7 [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//! ```
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020014//! let (sender, receiver) = crossbeam::channel::unbounded();
15//! #
16//! # // A future that will get spawned.
17//! # let future = async { 1 + 2 };
18//! #
19//! # // A function that schedules the task when it gets woken up.
20//! # let schedule = move |task| sender.send(task).unwrap();
21//! #
22//! # // Construct a task.
23//! # let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020024//! ```
25//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020026//! A task is constructed using the [`spawn`] function:
Stjepan Glavina1479e862019-08-12 20:18:51 +020027//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020028//! ```
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020029//! # let (sender, receiver) = crossbeam::channel::unbounded();
30//! #
31//! // A future that will be spawned.
32//! let future = async { 1 + 2 };
Stjepan Glavina1479e862019-08-12 20:18:51 +020033//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020034//! // A function that schedules the task when it gets woken up.
35//! let schedule = move |task| sender.send(task).unwrap();
Stjepan Glavina1479e862019-08-12 20:18:51 +020036//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020037//! // Construct a task.
38//! let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020039//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020040//! // Push the task into the queue by invoking its schedule function.
41//! task.schedule();
42//! ```
Stjepan Glavina1479e862019-08-12 20:18:51 +020043//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020044//! The last argument to the [`spawn`] function is a *tag*, an arbitrary piece of data associated
45//! with the task. In most executors, this is typically a task identifier or task-local storage.
Stjepan Glavina1479e862019-08-12 20:18:51 +020046//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020047//! The function returns a runnable [`Task`] and a [`JoinHandle`] that can await the result.
Stjepan Glavina1479e862019-08-12 20:18:51 +020048//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020049//! # Execution
50//!
51//! Task executors have some kind of main loop that drives tasks to completion. That means taking
52//! runnable tasks out of the queue and running each one in order:
53//!
54//! ```no_run
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020055//! # let (sender, receiver) = crossbeam::channel::unbounded();
56//! #
57//! # // A future that will get spawned.
58//! # let future = async { 1 + 2 };
59//! #
60//! # // A function that schedules the task when it gets woken up.
61//! # let schedule = move |task| sender.send(task).unwrap();
62//! #
63//! # // Construct a task.
64//! # let (task, handle) = async_task::spawn(future, schedule, ());
65//! #
66//! # // Push the task into the queue by invoking its schedule function.
67//! # task.schedule();
68//! #
69//! for task in receiver {
70//! task.run();
71//! }
72//! ```
73//!
74//! When a task is run, its future gets polled. If polling does not complete the task, that means
75//! it's waiting for another future and needs to go to sleep. When woken up, its schedule function
76//! will be invoked, pushing it back into the queue so that it can be run again.
Stjepan Glavina1479e862019-08-12 20:18:51 +020077//!
78//! # Cancellation
79//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020080//! Both [`Task`] and [`JoinHandle`] have a method that cancels the task. When cancelled, the
81//! task's future will not be polled again and will get dropped instead.
82//!
83//! If cancelled by the [`Task`] instance, the task is destroyed immediately. If cancelled by the
84//! [`JoinHandle`] instance, it will be scheduled one more time and the next attempt to run it will
85//! simply destroy it.
Stjepan Glavina1479e862019-08-12 20:18:51 +020086//!
87//! # Performance
88//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020089//! Task construction incurs a single allocation only that holds its state, the schedule function,
90//! and the future or the result of the future if completed.
Stjepan Glavina1479e862019-08-12 20:18:51 +020091//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020092//! The layout of a task is equivalent to 4 words followed by the schedule function, and then by a
93//! union of the future and its output.
Stjepan Glavina1479e862019-08-12 20:18:51 +020094//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020095//! [`spawn`]: fn.spawn.html
Stjepan Glavina1479e862019-08-12 20:18:51 +020096//! [`Task`]: struct.Task.html
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020097//! [`JoinHandle`]: struct.JoinHandle.html
Stjepan Glavina1479e862019-08-12 20:18:51 +020098
99#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200100#![doc(test(attr(deny(rust_2018_idioms, warnings))))]
101#![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
Stjepan Glavina1479e862019-08-12 20:18:51 +0200102
103mod header;
104mod join_handle;
105mod raw;
106mod state;
107mod task;
108mod utils;
109
110pub use crate::join_handle::JoinHandle;
111pub use crate::task::{spawn, Task};