blob: c1391a2239a1b68546def35cacd828a798d77466 [file] [log] [blame]
Stjepan Glavina1479e862019-08-12 20:18:51 +02001//! Task abstraction for building executors.
2//!
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +01003//! # Spawning
4//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +02005//! To spawn a future onto an executor, we first need to allocate it on the heap and keep some
6//! state alongside it. The state indicates whether the future is ready for polling, waiting to be
7//! woken up, or completed. Such a future is called a *task*.
Stjepan Glavina1479e862019-08-12 20:18:51 +02008//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +02009//! All executors have some kind of queue that holds runnable tasks:
Stjepan Glavina1479e862019-08-12 20:18:51 +020010//!
11//! ```
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020012//! let (sender, receiver) = crossbeam::channel::unbounded();
13//! #
14//! # // A future that will get spawned.
15//! # let future = async { 1 + 2 };
16//! #
17//! # // A function that schedules the task when it gets woken up.
18//! # let schedule = move |task| sender.send(task).unwrap();
19//! #
20//! # // Construct a task.
21//! # let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020022//! ```
23//!
Stjepan Glavinafcfa4ab2019-11-25 18:39:17 +010024//! A task is constructed using either [`spawn`] or [`spawn_local`]:
Stjepan Glavina1479e862019-08-12 20:18:51 +020025//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020026//! ```
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020027//! # let (sender, receiver) = crossbeam::channel::unbounded();
28//! #
29//! // A future that will be spawned.
30//! let future = async { 1 + 2 };
Stjepan Glavina1479e862019-08-12 20:18:51 +020031//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020032//! // A function that schedules the task when it gets woken up.
33//! let schedule = move |task| sender.send(task).unwrap();
Stjepan Glavina1479e862019-08-12 20:18:51 +020034//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020035//! // Construct a task.
36//! let (task, handle) = async_task::spawn(future, schedule, ());
Stjepan Glavina1479e862019-08-12 20:18:51 +020037//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020038//! // Push the task into the queue by invoking its schedule function.
39//! task.schedule();
40//! ```
Stjepan Glavina1479e862019-08-12 20:18:51 +020041//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020042//! The last argument to the [`spawn`] function is a *tag*, an arbitrary piece of data associated
43//! with the task. In most executors, this is typically a task identifier or task-local storage.
Stjepan Glavina1479e862019-08-12 20:18:51 +020044//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020045//! The function returns a runnable [`Task`] and a [`JoinHandle`] that can await the result.
Stjepan Glavina1479e862019-08-12 20:18:51 +020046//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020047//! # Execution
48//!
49//! Task executors have some kind of main loop that drives tasks to completion. That means taking
50//! runnable tasks out of the queue and running each one in order:
51//!
52//! ```no_run
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020053//! # let (sender, receiver) = crossbeam::channel::unbounded();
54//! #
55//! # // A future that will get spawned.
56//! # let future = async { 1 + 2 };
57//! #
58//! # // A function that schedules the task when it gets woken up.
59//! # let schedule = move |task| sender.send(task).unwrap();
60//! #
61//! # // Construct a task.
62//! # let (task, handle) = async_task::spawn(future, schedule, ());
63//! #
64//! # // Push the task into the queue by invoking its schedule function.
65//! # task.schedule();
66//! #
67//! for task in receiver {
68//! task.run();
69//! }
70//! ```
71//!
72//! When a task is run, its future gets polled. If polling does not complete the task, that means
73//! it's waiting for another future and needs to go to sleep. When woken up, its schedule function
74//! will be invoked, pushing it back into the queue so that it can be run again.
Stjepan Glavina1479e862019-08-12 20:18:51 +020075//!
76//! # Cancellation
77//!
Stjepan Glavina5c398cf2019-08-20 15:29:43 +020078//! Both [`Task`] and [`JoinHandle`] have methods that cancel the task. When cancelled, the task's
79//! future will not be polled again and will get dropped instead.
Stjepan Glavina7a8962b2019-08-16 11:25:25 +020080//!
81//! If cancelled by the [`Task`] instance, the task is destroyed immediately. If cancelled by the
82//! [`JoinHandle`] instance, it will be scheduled one more time and the next attempt to run it will
83//! simply destroy it.
Stjepan Glavina1479e862019-08-12 20:18:51 +020084//!
85//! # Performance
86//!
Stjepan Glavina5c398cf2019-08-20 15:29:43 +020087//! Task construction incurs a single allocation that holds its state, the schedule function, and
88//! the future or the result of the future if completed.
Stjepan Glavina1479e862019-08-12 20:18:51 +020089//!
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +010090//! The layout of a task is equivalent to 4 `usize`s followed by the schedule function, and then by
91//! a union of the future and its output.
92//!
93//! # Waking
94//!
95//! The handy [`waker_fn`] constructor converts any function into a [`Waker`]. Every time it is
96//! woken, the function gets called:
97//!
98//! ```
99//! let waker = async_task::waker_fn(|| println!("Wake!"));
100//!
101//! // Prints "Wake!" twice.
102//! waker.wake_by_ref();
103//! waker.wake_by_ref();
104//! ```
105//!
106//! This is useful for implementing single-future executors like [`block_on`].
Stjepan Glavina1479e862019-08-12 20:18:51 +0200107//!
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200108//! [`spawn`]: fn.spawn.html
Stjepan Glavinafcfa4ab2019-11-25 18:39:17 +0100109//! [`spawn_local`]: fn.spawn_local.html
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +0100110//! [`waker_fn`]: fn.waker_fn.html
Stjepan Glavina1479e862019-08-12 20:18:51 +0200111//! [`Task`]: struct.Task.html
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200112//! [`JoinHandle`]: struct.JoinHandle.html
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +0100113//! [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
114//! [`block_on`]: https://github.com/async-rs/async-task/blob/master/examples/block.rs
Stjepan Glavina1479e862019-08-12 20:18:51 +0200115
Stjepan Glavina921e8a02020-01-06 14:31:28 -0600116#![no_std]
Stjepan Glavina1479e862019-08-12 20:18:51 +0200117#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
Stjepan Glavina7a8962b2019-08-16 11:25:25 +0200118#![doc(test(attr(deny(rust_2018_idioms, warnings))))]
119#![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
Stjepan Glavina1479e862019-08-12 20:18:51 +0200120
Stjepan Glavina921e8a02020-01-06 14:31:28 -0600121extern crate alloc;
122
Stjepan Glavina1479e862019-08-12 20:18:51 +0200123mod header;
124mod join_handle;
125mod raw;
126mod state;
127mod task;
128mod utils;
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +0100129mod waker_fn;
Stjepan Glavina1479e862019-08-12 20:18:51 +0200130
131pub use crate::join_handle::JoinHandle;
Stjepan Glavinab7a24962020-02-03 15:18:01 +0100132pub use crate::task::{spawn, Task};
Stjepan Glavinaa94d2f42020-01-25 00:14:33 +0100133pub use crate::waker_fn::waker_fn;
Stjepan Glavinab7a24962020-02-03 15:18:01 +0100134
135#[cfg(any(unix, windows))]
136pub use crate::task::spawn_local;