14682 lines
357 KiB
Markdown
14682 lines
357 KiB
Markdown
# Crate Documentation
|
|
|
|
**Version:** 1.48.0
|
|
|
|
**Format Version:** 56
|
|
|
|
# Module `tokio`
|
|
|
|
A runtime for writing reliable network applications without compromising speed.
|
|
|
|
Tokio is an event-driven, non-blocking I/O platform for writing asynchronous
|
|
applications with the Rust programming language. At a high level, it
|
|
provides a few major components:
|
|
|
|
* Tools for [working with asynchronous tasks][tasks], including
|
|
[synchronization primitives and channels][sync] and [timeouts, sleeps, and
|
|
intervals][time].
|
|
* APIs for [performing asynchronous I/O][io], including [TCP and UDP][net] sockets,
|
|
[filesystem][fs] operations, and [process] and [signal] management.
|
|
* A [runtime] for executing asynchronous code, including a task scheduler,
|
|
an I/O driver backed by the operating system's event queue (`epoll`, `kqueue`,
|
|
`IOCP`, etc...), and a high performance timer.
|
|
|
|
Guide level documentation is found on the [website].
|
|
|
|
[tasks]: #working-with-tasks
|
|
[sync]: crate::sync
|
|
[time]: crate::time
|
|
[io]: #asynchronous-io
|
|
[net]: crate::net
|
|
[fs]: crate::fs
|
|
[process]: crate::process
|
|
[signal]: crate::signal
|
|
[fs]: crate::fs
|
|
[runtime]: crate::runtime
|
|
[website]: https://tokio.rs/tokio/tutorial
|
|
|
|
# A Tour of Tokio
|
|
|
|
Tokio consists of a number of modules that provide a range of functionality
|
|
essential for implementing asynchronous applications in Rust. In this
|
|
section, we will take a brief tour of Tokio, summarizing the major APIs and
|
|
their uses.
|
|
|
|
The easiest way to get started is to enable all features. Do this by
|
|
enabling the `full` feature flag:
|
|
|
|
```toml
|
|
tokio = { version = "1", features = ["full"] }
|
|
```
|
|
|
|
### Authoring applications
|
|
|
|
Tokio is great for writing applications and most users in this case shouldn't
|
|
worry too much about what features they should pick. If you're unsure, we suggest
|
|
going with `full` to ensure that you don't run into any road blocks while you're
|
|
building your application.
|
|
|
|
#### Example
|
|
|
|
This example shows the quickest way to get started with Tokio.
|
|
|
|
```toml
|
|
tokio = { version = "1", features = ["full"] }
|
|
```
|
|
|
|
### Authoring libraries
|
|
|
|
As a library author your goal should be to provide the lightest weight crate
|
|
that is based on Tokio. To achieve this you should ensure that you only enable
|
|
the features you need. This allows users to pick up your crate without having
|
|
to enable unnecessary features.
|
|
|
|
#### Example
|
|
|
|
This example shows how you may want to import features for a library that just
|
|
needs to `tokio::spawn` and use a `TcpStream`.
|
|
|
|
```toml
|
|
tokio = { version = "1", features = ["rt", "net"] }
|
|
```
|
|
|
|
## Working With Tasks
|
|
|
|
Asynchronous programs in Rust are based around lightweight, non-blocking
|
|
units of execution called [_tasks_][tasks]. The [`tokio::task`] module provides
|
|
important tools for working with tasks:
|
|
|
|
* The [`spawn`] function and [`JoinHandle`] type, for scheduling a new task
|
|
on the Tokio runtime and awaiting the output of a spawned task, respectively,
|
|
* Functions for [running blocking operations][blocking] in an asynchronous
|
|
task context.
|
|
|
|
The [`tokio::task`] module is present only when the "rt" feature flag
|
|
is enabled.
|
|
|
|
[tasks]: task/index.html#what-are-tasks
|
|
[`tokio::task`]: crate::task
|
|
[`spawn`]: crate::task::spawn()
|
|
[`JoinHandle`]: crate::task::JoinHandle
|
|
[blocking]: task/index.html#blocking-and-yielding
|
|
|
|
The [`tokio::sync`] module contains synchronization primitives to use when
|
|
needing to communicate or share data. These include:
|
|
|
|
* channels ([`oneshot`], [`mpsc`], [`watch`], and [`broadcast`]), for sending values
|
|
between tasks,
|
|
* a non-blocking [`Mutex`], for controlling access to a shared, mutable
|
|
value,
|
|
* an asynchronous [`Barrier`] type, for multiple tasks to synchronize before
|
|
beginning a computation.
|
|
|
|
The `tokio::sync` module is present only when the "sync" feature flag is
|
|
enabled.
|
|
|
|
[`tokio::sync`]: crate::sync
|
|
[`Mutex`]: crate::sync::Mutex
|
|
[`Barrier`]: crate::sync::Barrier
|
|
[`oneshot`]: crate::sync::oneshot
|
|
[`mpsc`]: crate::sync::mpsc
|
|
[`watch`]: crate::sync::watch
|
|
[`broadcast`]: crate::sync::broadcast
|
|
|
|
The [`tokio::time`] module provides utilities for tracking time and
|
|
scheduling work. This includes functions for setting [timeouts][timeout] for
|
|
tasks, [sleeping][sleep] work to run in the future, or [repeating an operation at an
|
|
interval][interval].
|
|
|
|
In order to use `tokio::time`, the "time" feature flag must be enabled.
|
|
|
|
[`tokio::time`]: crate::time
|
|
[sleep]: crate::time::sleep()
|
|
[interval]: crate::time::interval()
|
|
[timeout]: crate::time::timeout()
|
|
|
|
Finally, Tokio provides a _runtime_ for executing asynchronous tasks. Most
|
|
applications can use the [`#[tokio::main]`][main] macro to run their code on the
|
|
Tokio runtime. However, this macro provides only basic configuration options. As
|
|
an alternative, the [`tokio::runtime`] module provides more powerful APIs for configuring
|
|
and managing runtimes. You should use that module if the `#[tokio::main]` macro doesn't
|
|
provide the functionality you need.
|
|
|
|
Using the runtime requires the "rt" or "rt-multi-thread" feature flags, to
|
|
enable the current-thread [single-threaded scheduler][rt] and the [multi-thread
|
|
scheduler][rt-multi-thread], respectively. See the [`runtime` module
|
|
documentation][rt-features] for details. In addition, the "macros" feature
|
|
flag enables the `#[tokio::main]` and `#[tokio::test]` attributes.
|
|
|
|
[main]: attr.main.html
|
|
[`tokio::runtime`]: crate::runtime
|
|
[`Builder`]: crate::runtime::Builder
|
|
[`Runtime`]: crate::runtime::Runtime
|
|
[rt]: runtime/index.html#current-thread-scheduler
|
|
[rt-multi-thread]: runtime/index.html#multi-thread-scheduler
|
|
[rt-features]: runtime/index.html#runtime-scheduler
|
|
|
|
## CPU-bound tasks and blocking code
|
|
|
|
Tokio is able to concurrently run many tasks on a few threads by repeatedly
|
|
swapping the currently running task on each thread. However, this kind of
|
|
swapping can only happen at `.await` points, so code that spends a long time
|
|
without reaching an `.await` will prevent other tasks from running. To
|
|
combat this, Tokio provides two kinds of threads: Core threads and blocking threads.
|
|
|
|
The core threads are where all asynchronous code runs, and Tokio will by default
|
|
spawn one for each CPU core. You can use the environment variable `TOKIO_WORKER_THREADS`
|
|
to override the default value.
|
|
|
|
The blocking threads are spawned on demand, can be used to run blocking code
|
|
that would otherwise block other tasks from running and are kept alive when
|
|
not used for a certain amount of time which can be configured with [`thread_keep_alive`].
|
|
Since it is not possible for Tokio to swap out blocking tasks, like it
|
|
can do with asynchronous code, the upper limit on the number of blocking
|
|
threads is very large. These limits can be configured on the [`Builder`].
|
|
|
|
To spawn a blocking task, you should use the [`spawn_blocking`] function.
|
|
|
|
[`Builder`]: crate::runtime::Builder
|
|
[`spawn_blocking`]: crate::task::spawn_blocking()
|
|
[`thread_keep_alive`]: crate::runtime::Builder::thread_keep_alive()
|
|
|
|
```
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// This is running on a core thread.
|
|
|
|
let blocking_task = tokio::task::spawn_blocking(|| {
|
|
// This is running on a blocking thread.
|
|
// Blocking here is ok.
|
|
});
|
|
|
|
// We can wait for the blocking task like this:
|
|
// If the blocking task panics, the unwrap below will propagate the
|
|
// panic.
|
|
blocking_task.await.unwrap();
|
|
}
|
|
# }
|
|
```
|
|
|
|
If your code is CPU-bound and you wish to limit the number of threads used
|
|
to run it, you should use a separate thread pool dedicated to CPU bound tasks.
|
|
For example, you could consider using the [rayon] library for CPU-bound
|
|
tasks. It is also possible to create an extra Tokio runtime dedicated to
|
|
CPU-bound tasks, but if you do this, you should be careful that the extra
|
|
runtime runs _only_ CPU-bound tasks, as IO-bound tasks on that runtime
|
|
will behave poorly.
|
|
|
|
Hint: If using rayon, you can use a [`oneshot`] channel to send the result back
|
|
to Tokio when the rayon task finishes.
|
|
|
|
[rayon]: https://docs.rs/rayon
|
|
[`oneshot`]: crate::sync::oneshot
|
|
|
|
## Asynchronous IO
|
|
|
|
As well as scheduling and running tasks, Tokio provides everything you need
|
|
to perform input and output asynchronously.
|
|
|
|
The [`tokio::io`] module provides Tokio's asynchronous core I/O primitives,
|
|
the [`AsyncRead`], [`AsyncWrite`], and [`AsyncBufRead`] traits. In addition,
|
|
when the "io-util" feature flag is enabled, it also provides combinators and
|
|
functions for working with these traits, forming as an asynchronous
|
|
counterpart to [`std::io`].
|
|
|
|
Tokio also includes APIs for performing various kinds of I/O and interacting
|
|
with the operating system asynchronously. These include:
|
|
|
|
* [`tokio::net`], which contains non-blocking versions of [TCP], [UDP], and
|
|
[Unix Domain Sockets][UDS] (enabled by the "net" feature flag),
|
|
* [`tokio::fs`], similar to [`std::fs`] but for performing filesystem I/O
|
|
asynchronously (enabled by the "fs" feature flag),
|
|
* [`tokio::signal`], for asynchronously handling Unix and Windows OS signals
|
|
(enabled by the "signal" feature flag),
|
|
* [`tokio::process`], for spawning and managing child processes (enabled by
|
|
the "process" feature flag).
|
|
|
|
[`tokio::io`]: crate::io
|
|
[`AsyncRead`]: crate::io::AsyncRead
|
|
[`AsyncWrite`]: crate::io::AsyncWrite
|
|
[`AsyncBufRead`]: crate::io::AsyncBufRead
|
|
[`std::io`]: std::io
|
|
[`tokio::net`]: crate::net
|
|
[TCP]: crate::net::tcp
|
|
[UDP]: crate::net::UdpSocket
|
|
[UDS]: crate::net::unix
|
|
[`tokio::fs`]: crate::fs
|
|
[`std::fs`]: std::fs
|
|
[`tokio::signal`]: crate::signal
|
|
[`tokio::process`]: crate::process
|
|
|
|
# Examples
|
|
|
|
A simple TCP echo server:
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::net::TcpListener;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let listener = TcpListener::bind("127.0.0.1:8080").await?;
|
|
|
|
loop {
|
|
let (mut socket, _) = listener.accept().await?;
|
|
|
|
tokio::spawn(async move {
|
|
let mut buf = [0; 1024];
|
|
|
|
// In a loop, read data from the socket and write the data back.
|
|
loop {
|
|
let n = match socket.read(&mut buf).await {
|
|
// socket closed
|
|
Ok(0) => return,
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
eprintln!("failed to read from socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Write the data back
|
|
if let Err(e) = socket.write_all(&buf[0..n]).await {
|
|
eprintln!("failed to write to socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
# Feature flags
|
|
|
|
Tokio uses a set of [feature flags] to reduce the amount of compiled code. It
|
|
is possible to just enable certain features over others. By default, Tokio
|
|
does not enable any features but allows one to enable a subset for their use
|
|
case. Below is a list of the available feature flags. You may also notice
|
|
above each function, struct and trait there is listed one or more feature flags
|
|
that are required for that item to be used. If you are new to Tokio it is
|
|
recommended that you use the `full` feature flag which will enable all public APIs.
|
|
Beware though that this will pull in many extra dependencies that you may not
|
|
need.
|
|
|
|
- `full`: Enables all features listed below except `test-util` and `tracing`.
|
|
- `rt`: Enables `tokio::spawn`, the current-thread scheduler,
|
|
and non-scheduler utilities.
|
|
- `rt-multi-thread`: Enables the heavier, multi-threaded, work-stealing scheduler.
|
|
- `io-util`: Enables the IO based `Ext` traits.
|
|
- `io-std`: Enable `Stdout`, `Stdin` and `Stderr` types.
|
|
- `net`: Enables `tokio::net` types such as `TcpStream`, `UnixStream` and
|
|
`UdpSocket`, as well as (on Unix-like systems) `AsyncFd` and (on
|
|
FreeBSD) `PollAio`.
|
|
- `time`: Enables `tokio::time` types and allows the schedulers to enable
|
|
the built in timer.
|
|
- `process`: Enables `tokio::process` types.
|
|
- `macros`: Enables `#[tokio::main]` and `#[tokio::test]` macros.
|
|
- `sync`: Enables all `tokio::sync` types.
|
|
- `signal`: Enables all `tokio::signal` types.
|
|
- `fs`: Enables `tokio::fs` types.
|
|
- `test-util`: Enables testing based infrastructure for the Tokio runtime.
|
|
- `parking_lot`: As a potential optimization, use the [`parking_lot`] crate's
|
|
synchronization primitives internally. Also, this
|
|
dependency is necessary to construct some of our primitives
|
|
in a `const` context. `MSRV` may increase according to the
|
|
[`parking_lot`] release in use.
|
|
|
|
_Note: `AsyncRead` and `AsyncWrite` traits do not require any features and are
|
|
always available._
|
|
|
|
## Unstable features
|
|
|
|
Some feature flags are only available when specifying the `tokio_unstable` flag:
|
|
|
|
- `tracing`: Enables tracing events.
|
|
|
|
Likewise, some parts of the API are only available with the same flag:
|
|
|
|
- [`task::Builder`]
|
|
- Some methods on [`task::JoinSet`]
|
|
- [`runtime::RuntimeMetrics`]
|
|
- [`runtime::Builder::on_task_spawn`]
|
|
- [`runtime::Builder::on_task_terminate`]
|
|
- [`runtime::Builder::unhandled_panic`]
|
|
- [`runtime::TaskMeta`]
|
|
|
|
This flag enables **unstable** features. The public API of these features
|
|
may break in 1.x releases. To enable these features, the `--cfg
|
|
tokio_unstable` argument must be passed to `rustc` when compiling. This
|
|
serves to explicitly opt-in to features which may break semver conventions,
|
|
since Cargo [does not yet directly support such opt-ins][unstable features].
|
|
|
|
You can specify it in your project's `.cargo/config.toml` file:
|
|
|
|
```toml
|
|
[build]
|
|
rustflags = ["--cfg", "tokio_unstable"]
|
|
```
|
|
|
|
<div class="warning">
|
|
The <code>[build]</code> section does <strong>not</strong> go in a
|
|
<code>Cargo.toml</code> file. Instead it must be placed in the Cargo config
|
|
file <code>.cargo/config.toml</code>.
|
|
</div>
|
|
|
|
Alternatively, you can specify it with an environment variable:
|
|
|
|
```sh
|
|
## Many *nix shells:
|
|
export RUSTFLAGS="--cfg tokio_unstable"
|
|
cargo build
|
|
```
|
|
|
|
```powershell
|
|
## Windows PowerShell:
|
|
$Env:RUSTFLAGS="--cfg tokio_unstable"
|
|
cargo build
|
|
```
|
|
|
|
[unstable features]: https://internals.rust-lang.org/t/feature-request-unstable-opt-in-non-transitive-crate-features/16193#why-not-a-crate-feature-2
|
|
[feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
|
|
|
|
# Supported platforms
|
|
|
|
Tokio currently guarantees support for the following platforms:
|
|
|
|
* Linux
|
|
* Windows
|
|
* Android (API level 21)
|
|
* macOS
|
|
* iOS
|
|
* FreeBSD
|
|
|
|
Tokio will continue to support these platforms in the future. However,
|
|
future releases may change requirements such as the minimum required libc
|
|
version on Linux, the API level on Android, or the supported FreeBSD
|
|
release.
|
|
|
|
Beyond the above platforms, Tokio is intended to work on all platforms
|
|
supported by the mio crate. You can find a longer list [in mio's
|
|
documentation][mio-supported]. However, these additional platforms may
|
|
become unsupported in the future.
|
|
|
|
Note that Wine is considered to be a different platform from Windows. See
|
|
mio's documentation for more information on Wine support.
|
|
|
|
[mio-supported]: https://crates.io/crates/mio#platforms
|
|
|
|
## `WASM` support
|
|
|
|
Tokio has some limited support for the `WASM` platform. Without the
|
|
`tokio_unstable` flag, the following features are supported:
|
|
|
|
* `sync`
|
|
* `macros`
|
|
* `io-util`
|
|
* `rt`
|
|
* `time`
|
|
|
|
Enabling any other feature (including `full`) will cause a compilation
|
|
failure.
|
|
|
|
The `time` module will only work on `WASM` platforms that have support for
|
|
timers (e.g. wasm32-wasi). The timing functions will panic if used on a `WASM`
|
|
platform that does not support timers.
|
|
|
|
Note also that if the runtime becomes indefinitely idle, it will panic
|
|
immediately instead of blocking forever. On platforms that don't support
|
|
time, this means that the runtime can never be idle in any way.
|
|
|
|
## Unstable `WASM` support
|
|
|
|
Tokio also has unstable support for some additional `WASM` features. This
|
|
requires the use of the `tokio_unstable` flag.
|
|
|
|
Using this flag enables the use of `tokio::net` on the wasm32-wasi target.
|
|
However, not all methods are available on the networking types as `WASI`
|
|
currently does not support the creation of new sockets from within `WASM`.
|
|
Because of this, sockets must currently be created via the `FromRawFd`
|
|
trait.
|
|
|
|
## Modules
|
|
|
|
## Module `fs`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"fs\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"fs\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"fs\"))]")`
|
|
- `Other("#[<cfg>(not(loom))]")`
|
|
|
|
Asynchronous file utilities.
|
|
|
|
This module contains utility methods for working with the file system
|
|
asynchronously. This includes reading/writing to files, and working with
|
|
directories.
|
|
|
|
Be aware that most operating systems do not provide asynchronous file system
|
|
APIs. Because of that, Tokio will use ordinary blocking file operations
|
|
behind the scenes. This is done using the [`spawn_blocking`] threadpool to
|
|
run them in the background.
|
|
|
|
The `tokio::fs` module should only be used for ordinary files. Trying to use
|
|
it with e.g., a named pipe on Linux can result in surprising behavior,
|
|
such as hangs during runtime shutdown. For special files, you should use a
|
|
dedicated type such as [`tokio::net::unix::pipe`] or [`AsyncFd`] instead.
|
|
|
|
Currently, Tokio will always use [`spawn_blocking`] on all platforms, but it
|
|
may be changed to use asynchronous file system APIs such as io_uring in the
|
|
future.
|
|
|
|
# Usage
|
|
|
|
The easiest way to use this module is to use the utility functions that
|
|
operate on entire files:
|
|
|
|
* [`tokio::fs::read`](fn@crate::fs::read)
|
|
* [`tokio::fs::read_to_string`](fn@crate::fs::read_to_string)
|
|
* [`tokio::fs::write`](fn@crate::fs::write)
|
|
|
|
The two `read` functions reads the entire file and returns its contents.
|
|
The `write` function takes the contents of the file and writes those
|
|
contents to the file. It overwrites the existing file, if any.
|
|
|
|
For example, to read the file:
|
|
|
|
```
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let contents = tokio::fs::read_to_string("my_file.txt").await?;
|
|
|
|
println!("File has {} lines.", contents.lines().count());
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
To overwrite the file:
|
|
|
|
```
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let contents = "First line.\nSecond line.\nThird line.\n";
|
|
|
|
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
## Using `File`
|
|
|
|
The main type for interacting with files is [`File`]. It can be used to read
|
|
from and write to a given file. This is done using the [`AsyncRead`] and
|
|
[`AsyncWrite`] traits. This type is generally used when you want to do
|
|
something more complex than just reading or writing the entire contents in
|
|
one go.
|
|
|
|
**Note:** It is important to use [`flush`] when writing to a Tokio
|
|
[`File`]. This is because calls to `write` will return before the write has
|
|
finished, and [`flush`] will wait for the write to finish. (The write will
|
|
happen even if you don't flush; it will just happen later.) This is
|
|
different from [`std::fs::File`], and is due to the fact that `File` uses
|
|
`spawn_blocking` behind the scenes.
|
|
|
|
For example, to count the number of lines in a file without loading the
|
|
entire file into memory:
|
|
|
|
```no_run
|
|
use tokio::fs::File;
|
|
use tokio::io::AsyncReadExt;
|
|
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let mut file = File::open("my_file.txt").await?;
|
|
|
|
let mut chunk = vec![0; 4096];
|
|
let mut number_of_lines = 0;
|
|
loop {
|
|
let len = file.read(&mut chunk).await?;
|
|
if len == 0 {
|
|
// Length of zero means end of file.
|
|
break;
|
|
}
|
|
for &b in &chunk[..len] {
|
|
if b == b'\n' {
|
|
number_of_lines += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
println!("File has {} lines.", number_of_lines);
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
For example, to write a file line-by-line:
|
|
|
|
```no_run
|
|
use tokio::fs::File;
|
|
use tokio::io::AsyncWriteExt;
|
|
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let mut file = File::create("my_file.txt").await?;
|
|
|
|
file.write_all(b"First line.\n").await?;
|
|
file.write_all(b"Second line.\n").await?;
|
|
file.write_all(b"Third line.\n").await?;
|
|
|
|
// Remember to call `flush` after writing!
|
|
file.flush().await?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
## Tuning your file IO
|
|
|
|
Tokio's file uses [`spawn_blocking`] behind the scenes, and this has serious
|
|
performance consequences. To get good performance with file IO on Tokio, it
|
|
is recommended to batch your operations into as few `spawn_blocking` calls
|
|
as possible.
|
|
|
|
One example of this difference can be seen by comparing the two reading
|
|
examples above. The first example uses [`tokio::fs::read`], which reads the
|
|
entire file in a single `spawn_blocking` call, and then returns it. The
|
|
second example will read the file in chunks using many `spawn_blocking`
|
|
calls. This means that the second example will most likely be more expensive
|
|
for large files. (Of course, using chunks may be necessary for very large
|
|
files that don't fit in memory.)
|
|
|
|
The following examples will show some strategies for this:
|
|
|
|
When creating a file, write the data to a `String` or `Vec<u8>` and then
|
|
write the entire file in a single `spawn_blocking` call with
|
|
`tokio::fs::write`.
|
|
|
|
```no_run
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let mut contents = String::new();
|
|
|
|
contents.push_str("First line.\n");
|
|
contents.push_str("Second line.\n");
|
|
contents.push_str("Third line.\n");
|
|
|
|
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
Use [`BufReader`] and [`BufWriter`] to buffer many small reads or writes
|
|
into a few large ones. This example will most likely only perform one
|
|
`spawn_blocking` call.
|
|
|
|
```no_run
|
|
use tokio::fs::File;
|
|
use tokio::io::{AsyncWriteExt, BufWriter};
|
|
|
|
# async fn dox() -> std::io::Result<()> {
|
|
let mut file = BufWriter::new(File::create("my_file.txt").await?);
|
|
|
|
file.write_all(b"First line.\n").await?;
|
|
file.write_all(b"Second line.\n").await?;
|
|
file.write_all(b"Third line.\n").await?;
|
|
|
|
// Due to the BufWriter, the actual write and spawn_blocking
|
|
// call happens when you flush.
|
|
file.flush().await?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
Manually use [`std::fs`] inside [`spawn_blocking`].
|
|
|
|
```no_run
|
|
use std::fs::File;
|
|
use std::io::{self, Write};
|
|
use tokio::task::spawn_blocking;
|
|
|
|
# async fn dox() -> std::io::Result<()> {
|
|
spawn_blocking(move || {
|
|
let mut file = File::create("my_file.txt")?;
|
|
|
|
file.write_all(b"First line.\n")?;
|
|
file.write_all(b"Second line.\n")?;
|
|
file.write_all(b"Third line.\n")?;
|
|
|
|
// Unlike Tokio's file, the std::fs file does
|
|
// not need flush.
|
|
|
|
io::Result::Ok(())
|
|
}).await.unwrap()?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
It's also good to be aware of [`File::set_max_buf_size`], which controls the
|
|
maximum amount of bytes that Tokio's [`File`] will read or write in a single
|
|
[`spawn_blocking`] call. The default is two megabytes, but this is subject
|
|
to change.
|
|
|
|
[`spawn_blocking`]: fn@crate::task::spawn_blocking
|
|
[`AsyncRead`]: trait@crate::io::AsyncRead
|
|
[`AsyncWrite`]: trait@crate::io::AsyncWrite
|
|
[`BufReader`]: struct@crate::io::BufReader
|
|
[`BufWriter`]: struct@crate::io::BufWriter
|
|
[`tokio::net::unix::pipe`]: crate::net::unix::pipe
|
|
[`AsyncFd`]: crate::io::unix::AsyncFd
|
|
[`flush`]: crate::io::AsyncWriteExt::flush
|
|
[`tokio::fs::read`]: fn@crate::fs::read
|
|
|
|
```rust
|
|
pub mod fs { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `canonicalize`
|
|
|
|
```rust
|
|
pub use self::canonicalize::canonicalize;
|
|
```
|
|
|
|
#### Re-export `create_dir`
|
|
|
|
```rust
|
|
pub use self::create_dir::create_dir;
|
|
```
|
|
|
|
#### Re-export `create_dir_all`
|
|
|
|
```rust
|
|
pub use self::create_dir_all::create_dir_all;
|
|
```
|
|
|
|
#### Re-export `DirBuilder`
|
|
|
|
```rust
|
|
pub use self::dir_builder::DirBuilder;
|
|
```
|
|
|
|
#### Re-export `File`
|
|
|
|
```rust
|
|
pub use self::file::File;
|
|
```
|
|
|
|
#### Re-export `hard_link`
|
|
|
|
```rust
|
|
pub use self::hard_link::hard_link;
|
|
```
|
|
|
|
#### Re-export `metadata`
|
|
|
|
```rust
|
|
pub use self::metadata::metadata;
|
|
```
|
|
|
|
#### Re-export `OpenOptions`
|
|
|
|
```rust
|
|
pub use self::open_options::OpenOptions;
|
|
```
|
|
|
|
#### Re-export `read`
|
|
|
|
```rust
|
|
pub use self::read::read;
|
|
```
|
|
|
|
#### Re-export `read_dir`
|
|
|
|
```rust
|
|
pub use self::read_dir::read_dir;
|
|
```
|
|
|
|
#### Re-export `DirEntry`
|
|
|
|
```rust
|
|
pub use self::read_dir::DirEntry;
|
|
```
|
|
|
|
#### Re-export `ReadDir`
|
|
|
|
```rust
|
|
pub use self::read_dir::ReadDir;
|
|
```
|
|
|
|
#### Re-export `read_link`
|
|
|
|
```rust
|
|
pub use self::read_link::read_link;
|
|
```
|
|
|
|
#### Re-export `read_to_string`
|
|
|
|
```rust
|
|
pub use self::read_to_string::read_to_string;
|
|
```
|
|
|
|
#### Re-export `remove_dir`
|
|
|
|
```rust
|
|
pub use self::remove_dir::remove_dir;
|
|
```
|
|
|
|
#### Re-export `remove_dir_all`
|
|
|
|
```rust
|
|
pub use self::remove_dir_all::remove_dir_all;
|
|
```
|
|
|
|
#### Re-export `remove_file`
|
|
|
|
```rust
|
|
pub use self::remove_file::remove_file;
|
|
```
|
|
|
|
#### Re-export `rename`
|
|
|
|
```rust
|
|
pub use self::rename::rename;
|
|
```
|
|
|
|
#### Re-export `set_permissions`
|
|
|
|
```rust
|
|
pub use self::set_permissions::set_permissions;
|
|
```
|
|
|
|
#### Re-export `symlink_metadata`
|
|
|
|
```rust
|
|
pub use self::symlink_metadata::symlink_metadata;
|
|
```
|
|
|
|
#### Re-export `write`
|
|
|
|
```rust
|
|
pub use self::write::write;
|
|
```
|
|
|
|
#### Re-export `copy`
|
|
|
|
```rust
|
|
pub use self::copy::copy;
|
|
```
|
|
|
|
#### Re-export `try_exists`
|
|
|
|
```rust
|
|
pub use self::try_exists::try_exists;
|
|
```
|
|
|
|
#### Re-export `symlink`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(unix)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(unix)))]")`
|
|
- `Other("#[doc(cfg(unix))]")`
|
|
|
|
```rust
|
|
pub use self::symlink::symlink;
|
|
```
|
|
|
|
#### Re-export `symlink_dir`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(all(doc, docsrs), windows))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(windows)))]")`
|
|
- `Other("#[doc(cfg(windows))]")`
|
|
|
|
```rust
|
|
pub use self::symlink_dir::symlink_dir;
|
|
```
|
|
|
|
#### Re-export `symlink_file`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(all(doc, docsrs), windows))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(windows)))]")`
|
|
- `Other("#[doc(cfg(windows))]")`
|
|
|
|
```rust
|
|
pub use self::symlink_file::symlink_file;
|
|
```
|
|
|
|
## Module `io`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(not(all(feature = \"rt\", feature = \"net\")),\nallow(dead_code, unused_imports))]")`
|
|
|
|
Traits, helpers, and type definitions for asynchronous I/O functionality.
|
|
|
|
This module is the asynchronous version of `std::io`. Primarily, it
|
|
defines two traits, [`AsyncRead`] and [`AsyncWrite`], which are asynchronous
|
|
versions of the [`Read`] and [`Write`] traits in the standard library.
|
|
|
|
# `AsyncRead` and `AsyncWrite`
|
|
|
|
Like the standard library's [`Read`] and [`Write`] traits, [`AsyncRead`] and
|
|
[`AsyncWrite`] provide the most general interface for reading and writing
|
|
input and output. Unlike the standard library's traits, however, they are
|
|
_asynchronous_ — meaning that reading from or writing to a `tokio::io`
|
|
type will _yield_ to the Tokio scheduler when IO is not ready, rather than
|
|
blocking. This allows other tasks to run while waiting on IO.
|
|
|
|
Another difference is that `AsyncRead` and `AsyncWrite` only contain
|
|
core methods needed to provide asynchronous reading and writing
|
|
functionality. Instead, utility methods are defined in the [`AsyncReadExt`]
|
|
and [`AsyncWriteExt`] extension traits. These traits are automatically
|
|
implemented for all values that implement `AsyncRead` and `AsyncWrite`
|
|
respectively.
|
|
|
|
End users will rarely interact directly with `AsyncRead` and
|
|
`AsyncWrite`. Instead, they will use the async functions defined in the
|
|
extension traits. Library authors are expected to implement `AsyncRead`
|
|
and `AsyncWrite` in order to provide types that behave like byte streams.
|
|
|
|
Even with these differences, Tokio's `AsyncRead` and `AsyncWrite` traits
|
|
can be used in almost exactly the same manner as the standard library's
|
|
`Read` and `Write`. Most types in the standard library that implement `Read`
|
|
and `Write` have asynchronous equivalents in `tokio` that implement
|
|
`AsyncRead` and `AsyncWrite`, such as [`File`] and [`TcpStream`].
|
|
|
|
For example, the standard library documentation introduces `Read` by
|
|
[demonstrating][std_example] reading some bytes from a [`std::fs::File`]. We
|
|
can do the same with [`tokio::fs::File`][`File`]:
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::io::{self, AsyncReadExt};
|
|
use tokio::fs::File;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> io::Result<()> {
|
|
let mut f = File::open("foo.txt").await?;
|
|
let mut buffer = [0; 10];
|
|
|
|
// read up to 10 bytes
|
|
let n = f.read(&mut buffer).await?;
|
|
|
|
println!("The bytes: {:?}", &buffer[..n]);
|
|
Ok(())
|
|
}
|
|
# }
|
|
```
|
|
|
|
[`File`]: crate::fs::File
|
|
[`TcpStream`]: crate::net::TcpStream
|
|
[`std::fs::File`]: std::fs::File
|
|
[std_example]: std::io#read-and-write
|
|
|
|
## Buffered Readers and Writers
|
|
|
|
Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
|
|
making near-constant calls to the operating system. To help with this,
|
|
`std::io` comes with [support for _buffered_ readers and writers][stdbuf],
|
|
and therefore, `tokio::io` does as well.
|
|
|
|
Tokio provides an async version of the [`std::io::BufRead`] trait,
|
|
[`AsyncBufRead`]; and async [`BufReader`] and [`BufWriter`] structs, which
|
|
wrap readers and writers. These wrappers use a buffer, reducing the number
|
|
of calls and providing nicer methods for accessing exactly what you want.
|
|
|
|
For example, [`BufReader`] works with the [`AsyncBufRead`] trait to add
|
|
extra methods to any async reader:
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::io::{self, BufReader, AsyncBufReadExt};
|
|
use tokio::fs::File;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> io::Result<()> {
|
|
let f = File::open("foo.txt").await?;
|
|
let mut reader = BufReader::new(f);
|
|
let mut buffer = String::new();
|
|
|
|
// read a line into buffer
|
|
reader.read_line(&mut buffer).await?;
|
|
|
|
println!("{}", buffer);
|
|
Ok(())
|
|
}
|
|
# }
|
|
```
|
|
|
|
[`BufWriter`] doesn't add any new ways of writing; it just buffers every call
|
|
to [`write`](crate::io::AsyncWriteExt::write). However, you **must** flush
|
|
[`BufWriter`] to ensure that any buffered data is written.
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::io::{self, BufWriter, AsyncWriteExt};
|
|
use tokio::fs::File;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> io::Result<()> {
|
|
let f = File::create("foo.txt").await?;
|
|
{
|
|
let mut writer = BufWriter::new(f);
|
|
|
|
// Write a byte to the buffer.
|
|
writer.write(&[42u8]).await?;
|
|
|
|
// Flush the buffer before it goes out of scope.
|
|
writer.flush().await?;
|
|
|
|
} // Unless flushed or shut down, the contents of the buffer is discarded on drop.
|
|
|
|
Ok(())
|
|
}
|
|
# }
|
|
```
|
|
|
|
[stdbuf]: std::io#bufreader-and-bufwriter
|
|
[`std::io::BufRead`]: std::io::BufRead
|
|
[`AsyncBufRead`]: crate::io::AsyncBufRead
|
|
[`BufReader`]: crate::io::BufReader
|
|
[`BufWriter`]: crate::io::BufWriter
|
|
|
|
## Implementing `AsyncRead` and `AsyncWrite`
|
|
|
|
Because they are traits, we can implement [`AsyncRead`] and [`AsyncWrite`] for
|
|
our own types, as well. Note that these traits must only be implemented for
|
|
non-blocking I/O types that integrate with the futures type system. In
|
|
other words, these types must never block the thread, and instead the
|
|
current task is notified when the I/O resource is ready.
|
|
|
|
## Conversion to and from Stream/Sink
|
|
|
|
It is often convenient to encapsulate the reading and writing of bytes in a
|
|
[`Stream`] or [`Sink`] of data.
|
|
|
|
Tokio provides simple wrappers for converting [`AsyncRead`] to [`Stream`]
|
|
and vice-versa in the [tokio-util] crate, see [`ReaderStream`] and
|
|
[`StreamReader`].
|
|
|
|
There are also utility traits that abstract the asynchronous buffering
|
|
necessary to write your own adaptors for encoding and decoding bytes to/from
|
|
your structured data, allowing to transform something that implements
|
|
[`AsyncRead`]/[`AsyncWrite`] into a [`Stream`]/[`Sink`], see [`Decoder`] and
|
|
[`Encoder`] in the [tokio-util::codec] module.
|
|
|
|
[tokio-util]: https://docs.rs/tokio-util
|
|
[tokio-util::codec]: https://docs.rs/tokio-util/latest/tokio_util/codec/index.html
|
|
|
|
# Standard input and output
|
|
|
|
Tokio provides asynchronous APIs to standard [input], [output], and [error].
|
|
These APIs are very similar to the ones provided by `std`, but they also
|
|
implement [`AsyncRead`] and [`AsyncWrite`].
|
|
|
|
Note that the standard input / output APIs **must** be used from the
|
|
context of the Tokio runtime, as they require Tokio-specific features to
|
|
function. Calling these functions outside of a Tokio runtime will panic.
|
|
|
|
[input]: fn@stdin
|
|
[output]: fn@stdout
|
|
[error]: fn@stderr
|
|
|
|
# `std` re-exports
|
|
|
|
Additionally, [`Error`], [`ErrorKind`], [`Result`], and [`SeekFrom`] are
|
|
re-exported from `std::io` for ease of use.
|
|
|
|
[`AsyncRead`]: trait@AsyncRead
|
|
[`AsyncWrite`]: trait@AsyncWrite
|
|
[`AsyncReadExt`]: trait@AsyncReadExt
|
|
[`AsyncWriteExt`]: trait@AsyncWriteExt
|
|
["codec"]: https://docs.rs/tokio-util/latest/tokio_util/codec/index.html
|
|
[`Encoder`]: https://docs.rs/tokio-util/latest/tokio_util/codec/trait.Encoder.html
|
|
[`Decoder`]: https://docs.rs/tokio-util/latest/tokio_util/codec/trait.Decoder.html
|
|
[`ReaderStream`]: https://docs.rs/tokio-util/latest/tokio_util/io/struct.ReaderStream.html
|
|
[`StreamReader`]: https://docs.rs/tokio-util/latest/tokio_util/io/struct.StreamReader.html
|
|
[`Error`]: struct@Error
|
|
[`ErrorKind`]: enum@ErrorKind
|
|
[`Result`]: type@Result
|
|
[`Read`]: std::io::Read
|
|
[`SeekFrom`]: enum@SeekFrom
|
|
[`Sink`]: https://docs.rs/futures/0.3/futures/sink/trait.Sink.html
|
|
[`Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
|
|
[`Write`]: std::io::Write
|
|
|
|
```rust
|
|
pub mod io { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `bsd`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(any(docsrs, target_os = \"freebsd\"), feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(target_os = \"freebsd\", feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(target_os = \"freebsd\", feature = \"net\")))]")`
|
|
|
|
BSD-specific I/O types.
|
|
|
|
```rust
|
|
pub mod bsd { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `Aio`
|
|
|
|
```rust
|
|
pub use poll_aio::Aio;
|
|
```
|
|
|
|
#### Re-export `AioEvent`
|
|
|
|
```rust
|
|
pub use poll_aio::AioEvent;
|
|
```
|
|
|
|
#### Re-export `AioSource`
|
|
|
|
```rust
|
|
pub use poll_aio::AioSource;
|
|
```
|
|
|
|
## Module `unix`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
Asynchronous IO structures specific to Unix-like operating systems.
|
|
|
|
```rust
|
|
pub mod unix { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `AsyncFd`
|
|
|
|
```rust
|
|
pub use super::async_fd::AsyncFd;
|
|
```
|
|
|
|
#### Re-export `AsyncFdTryNewError`
|
|
|
|
```rust
|
|
pub use super::async_fd::AsyncFdTryNewError;
|
|
```
|
|
|
|
#### Re-export `AsyncFdReadyGuard`
|
|
|
|
```rust
|
|
pub use super::async_fd::AsyncFdReadyGuard;
|
|
```
|
|
|
|
#### Re-export `AsyncFdReadyMutGuard`
|
|
|
|
```rust
|
|
pub use super::async_fd::AsyncFdReadyMutGuard;
|
|
```
|
|
|
|
#### Re-export `TryIoError`
|
|
|
|
```rust
|
|
pub use super::async_fd::TryIoError;
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `AsyncBufRead`
|
|
|
|
```rust
|
|
pub use self::async_buf_read::AsyncBufRead;
|
|
```
|
|
|
|
#### Re-export `AsyncRead`
|
|
|
|
```rust
|
|
pub use self::async_read::AsyncRead;
|
|
```
|
|
|
|
#### Re-export `AsyncSeek`
|
|
|
|
```rust
|
|
pub use self::async_seek::AsyncSeek;
|
|
```
|
|
|
|
#### Re-export `AsyncWrite`
|
|
|
|
```rust
|
|
pub use self::async_write::AsyncWrite;
|
|
```
|
|
|
|
#### Re-export `ReadBuf`
|
|
|
|
```rust
|
|
pub use self::read_buf::ReadBuf;
|
|
```
|
|
|
|
#### Re-export `Error`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(no_inline)]")`
|
|
|
|
```rust
|
|
pub use std::io::Error;
|
|
```
|
|
|
|
#### Re-export `ErrorKind`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(no_inline)]")`
|
|
|
|
```rust
|
|
pub use std::io::ErrorKind;
|
|
```
|
|
|
|
#### Re-export `Result`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(no_inline)]")`
|
|
|
|
```rust
|
|
pub use std::io::Result;
|
|
```
|
|
|
|
#### Re-export `SeekFrom`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(no_inline)]")`
|
|
|
|
```rust
|
|
pub use std::io::SeekFrom;
|
|
```
|
|
|
|
#### Re-export `Interest`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))]")`
|
|
- `Other("#[<cfg_attr>(docsrs,\ndoc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))))]")`
|
|
- `Other("#[doc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",))))]")`
|
|
|
|
```rust
|
|
pub use interest::Interest;
|
|
```
|
|
|
|
#### Re-export `Ready`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))]")`
|
|
- `Other("#[<cfg_attr>(docsrs,\ndoc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))))]")`
|
|
- `Other("#[doc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",))))]")`
|
|
|
|
```rust
|
|
pub use ready::Ready;
|
|
```
|
|
|
|
#### Re-export `stderr`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stderr::stderr;
|
|
```
|
|
|
|
#### Re-export `Stderr`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stderr::Stderr;
|
|
```
|
|
|
|
#### Re-export `stdin`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stdin::stdin;
|
|
```
|
|
|
|
#### Re-export `Stdin`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stdin::Stdin;
|
|
```
|
|
|
|
#### Re-export `stdout`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stdout::stdout;
|
|
```
|
|
|
|
#### Re-export `Stdout`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-std\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-std\"))]")`
|
|
|
|
```rust
|
|
pub use stdout::Stdout;
|
|
```
|
|
|
|
#### Re-export `split`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use split::split;
|
|
```
|
|
|
|
#### Re-export `ReadHalf`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use split::ReadHalf;
|
|
```
|
|
|
|
#### Re-export `WriteHalf`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use split::WriteHalf;
|
|
```
|
|
|
|
#### Re-export `join`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use join::join;
|
|
```
|
|
|
|
#### Re-export `Join`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use join::Join;
|
|
```
|
|
|
|
#### Re-export `copy`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::copy;
|
|
```
|
|
|
|
#### Re-export `copy_bidirectional`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::copy_bidirectional;
|
|
```
|
|
|
|
#### Re-export `copy_bidirectional_with_sizes`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::copy_bidirectional_with_sizes;
|
|
```
|
|
|
|
#### Re-export `copy_buf`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::copy_buf;
|
|
```
|
|
|
|
#### Re-export `duplex`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::duplex;
|
|
```
|
|
|
|
#### Re-export `empty`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::empty;
|
|
```
|
|
|
|
#### Re-export `repeat`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::repeat;
|
|
```
|
|
|
|
#### Re-export `sink`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::sink;
|
|
```
|
|
|
|
#### Re-export `simplex`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::simplex;
|
|
```
|
|
|
|
#### Re-export `AsyncBufReadExt`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::AsyncBufReadExt;
|
|
```
|
|
|
|
#### Re-export `AsyncReadExt`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::AsyncReadExt;
|
|
```
|
|
|
|
#### Re-export `AsyncSeekExt`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::AsyncSeekExt;
|
|
```
|
|
|
|
#### Re-export `AsyncWriteExt`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::AsyncWriteExt;
|
|
```
|
|
|
|
#### Re-export `BufReader`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::BufReader;
|
|
```
|
|
|
|
#### Re-export `BufStream`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::BufStream;
|
|
```
|
|
|
|
#### Re-export `BufWriter`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::BufWriter;
|
|
```
|
|
|
|
#### Re-export `Chain`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Chain;
|
|
```
|
|
|
|
#### Re-export `DuplexStream`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::DuplexStream;
|
|
```
|
|
|
|
#### Re-export `Empty`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Empty;
|
|
```
|
|
|
|
#### Re-export `Lines`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Lines;
|
|
```
|
|
|
|
#### Re-export `Repeat`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Repeat;
|
|
```
|
|
|
|
#### Re-export `Sink`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Sink;
|
|
```
|
|
|
|
#### Re-export `Split`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Split;
|
|
```
|
|
|
|
#### Re-export `Take`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::Take;
|
|
```
|
|
|
|
#### Re-export `SimplexStream`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"io-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"io-util\"))]")`
|
|
|
|
```rust
|
|
pub use util::SimplexStream;
|
|
```
|
|
|
|
## Module `net`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(not(loom))]")`
|
|
|
|
TCP/UDP/Unix bindings for `tokio`.
|
|
|
|
This module contains the TCP/UDP/Unix networking types, similar to the standard
|
|
library, which can be used to implement networking protocols.
|
|
|
|
# Organization
|
|
|
|
* [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP
|
|
* [`UdpSocket`] provides functionality for communication over UDP
|
|
* [`UnixListener`] and [`UnixStream`] provide functionality for communication over a
|
|
Unix Domain Stream Socket **(available on Unix only)**
|
|
* [`UnixDatagram`] provides functionality for communication
|
|
over Unix Domain Datagram Socket **(available on Unix only)**
|
|
* [`tokio::net::unix::pipe`] for FIFO pipes **(available on Unix only)**
|
|
* [`tokio::net::windows::named_pipe`] for Named Pipes **(available on Windows only)**
|
|
|
|
For IO resources not available in `tokio::net`, you can use [`AsyncFd`].
|
|
|
|
[`TcpListener`]: TcpListener
|
|
[`TcpStream`]: TcpStream
|
|
[`UdpSocket`]: UdpSocket
|
|
[`UnixListener`]: UnixListener
|
|
[`UnixStream`]: UnixStream
|
|
[`UnixDatagram`]: UnixDatagram
|
|
[`tokio::net::unix::pipe`]: unix::pipe
|
|
[`tokio::net::windows::named_pipe`]: windows::named_pipe
|
|
[`AsyncFd`]: crate::io::unix::AsyncFd
|
|
|
|
```rust
|
|
pub mod net { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `tcp`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"net\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"net\"))]")`
|
|
|
|
TCP utility types.
|
|
|
|
```rust
|
|
pub mod tcp { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `ReadHalf`
|
|
|
|
```rust
|
|
pub use split::ReadHalf;
|
|
```
|
|
|
|
#### Re-export `WriteHalf`
|
|
|
|
```rust
|
|
pub use split::WriteHalf;
|
|
```
|
|
|
|
#### Re-export `OwnedReadHalf`
|
|
|
|
```rust
|
|
pub use split_owned::OwnedReadHalf;
|
|
```
|
|
|
|
#### Re-export `OwnedWriteHalf`
|
|
|
|
```rust
|
|
pub use split_owned::OwnedWriteHalf;
|
|
```
|
|
|
|
#### Re-export `ReuniteError`
|
|
|
|
```rust
|
|
pub use split_owned::ReuniteError;
|
|
```
|
|
|
|
## Module `unix`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
Unix specific network types.
|
|
|
|
```rust
|
|
pub mod unix { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `pipe`
|
|
|
|
Unix pipe types.
|
|
|
|
```rust
|
|
pub mod pipe { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `OpenOptions`
|
|
|
|
Options and flags which can be used to configure how a FIFO file is opened.
|
|
|
|
This builder allows configuring how to create a pipe end from a FIFO file.
|
|
Generally speaking, when using `OpenOptions`, you'll first call [`new`],
|
|
then chain calls to methods to set each option, then call either
|
|
[`open_receiver`] or [`open_sender`], passing the path of the FIFO file you
|
|
are trying to open. This will give you a [`io::Result`] with a pipe end
|
|
inside that you can further operate on.
|
|
|
|
[`new`]: OpenOptions::new
|
|
[`open_receiver`]: OpenOptions::open_receiver
|
|
[`open_sender`]: OpenOptions::open_sender
|
|
|
|
# Examples
|
|
|
|
Opening a pair of pipe ends from a FIFO file:
|
|
|
|
```no_run
|
|
use tokio::net::unix::pipe;
|
|
# use std::error::Error;
|
|
|
|
const FIFO_NAME: &str = "path/to/a/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn Error>> {
|
|
let rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
|
|
let tx = pipe::OpenOptions::new().open_sender(FIFO_NAME)?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
Opening a [`Sender`] on Linux when you are sure the file is a FIFO:
|
|
|
|
```ignore
|
|
use tokio::net::unix::pipe;
|
|
use nix::{unistd::mkfifo, sys::stat::Mode};
|
|
# use std::error::Error;
|
|
|
|
// Our program has exclusive access to this path.
|
|
const FIFO_NAME: &str = "path/to/a/new/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn Error>> {
|
|
mkfifo(FIFO_NAME, Mode::S_IRWXU)?;
|
|
let tx = pipe::OpenOptions::new()
|
|
.read_write(true)
|
|
.unchecked(true)
|
|
.open_sender(FIFO_NAME)?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub struct OpenOptions {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new() -> OpenOptions { /* ... */ }
|
|
```
|
|
Creates a blank new set of options ready for configuration.
|
|
|
|
- ```rust
|
|
pub fn read_write(self: &mut Self, value: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Sets the option for read-write access.
|
|
|
|
- ```rust
|
|
pub fn unchecked(self: &mut Self, value: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Sets the option to skip the check for FIFO file type.
|
|
|
|
- ```rust
|
|
pub fn open_receiver<P: AsRef<Path>>(self: &Self, path: P) -> io::Result<Receiver> { /* ... */ }
|
|
```
|
|
Creates a [`Receiver`] from a FIFO file with the options specified by `self`.
|
|
|
|
- ```rust
|
|
pub fn open_sender<P: AsRef<Path>>(self: &Self, path: P) -> io::Result<Sender> { /* ... */ }
|
|
```
|
|
Creates a [`Sender`] from a FIFO file with the options specified by `self`.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> OpenOptions { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Default**
|
|
- ```rust
|
|
fn default() -> OpenOptions { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Sender`
|
|
|
|
Writing end of a Unix pipe.
|
|
|
|
It can be constructed from a FIFO file with [`OpenOptions::open_sender`].
|
|
|
|
Opening a named pipe for writing involves a few steps.
|
|
Call to [`OpenOptions::open_sender`] might fail with an error indicating
|
|
different things:
|
|
|
|
* [`io::ErrorKind::NotFound`] - There is no file at the specified path.
|
|
* [`io::ErrorKind::InvalidInput`] - The file exists, but it is not a FIFO.
|
|
* [`ENXIO`] - The file is a FIFO, but no process has it open for reading.
|
|
Sleep for a while and try again.
|
|
* Other OS errors not specific to opening FIFO files.
|
|
|
|
Opening a `Sender` from a FIFO file should look like this:
|
|
|
|
```no_run
|
|
use tokio::net::unix::pipe;
|
|
use tokio::time::{self, Duration};
|
|
|
|
const FIFO_NAME: &str = "path/to/a/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Wait for a reader to open the file.
|
|
let tx = loop {
|
|
match pipe::OpenOptions::new().open_sender(FIFO_NAME) {
|
|
Ok(tx) => break tx,
|
|
Err(e) if e.raw_os_error() == Some(libc::ENXIO) => {},
|
|
Err(e) => return Err(e.into()),
|
|
}
|
|
|
|
time::sleep(Duration::from_millis(50)).await;
|
|
};
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
On Linux, it is possible to create a `Sender` without waiting in a sleeping
|
|
loop. This is done by opening a named pipe in read-write access mode with
|
|
`OpenOptions::read_write`. This way, a `Sender` can at the same time hold
|
|
both a writing end and a reading end, and the latter allows to open a FIFO
|
|
without [`ENXIO`] error since the pipe is open for reading as well.
|
|
|
|
`Sender` cannot be used to read from a pipe, so in practice the read access
|
|
is only used when a FIFO is opened. However, using a `Sender` in read-write
|
|
mode **may lead to lost data**, because written data will be dropped by the
|
|
system as soon as all pipe ends are closed. To avoid lost data you have to
|
|
make sure that a reading end has been opened before dropping a `Sender`.
|
|
|
|
Note that using read-write access mode with FIFO files is not defined by
|
|
the POSIX standard and it is only guaranteed to work on Linux.
|
|
|
|
```ignore
|
|
use tokio::io::AsyncWriteExt;
|
|
use tokio::net::unix::pipe;
|
|
|
|
const FIFO_NAME: &str = "path/to/a/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut tx = pipe::OpenOptions::new()
|
|
.read_write(true)
|
|
.open_sender(FIFO_NAME)?;
|
|
|
|
// Asynchronously write to the pipe before a reader.
|
|
tx.write_all(b"hello world").await?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
[`ENXIO`]: https://docs.rs/libc/latest/libc/constant.ENXIO.html
|
|
|
|
```rust
|
|
pub struct Sender {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn from_file(file: File) -> io::Result<Sender> { /* ... */ }
|
|
```
|
|
Creates a new `Sender` from a [`File`].
|
|
|
|
- ```rust
|
|
pub fn from_owned_fd(owned_fd: OwnedFd) -> io::Result<Sender> { /* ... */ }
|
|
```
|
|
Creates a new `Sender` from an [`OwnedFd`].
|
|
|
|
- ```rust
|
|
pub fn from_file_unchecked(file: File) -> io::Result<Sender> { /* ... */ }
|
|
```
|
|
Creates a new `Sender` from a [`File`] without checking pipe properties.
|
|
|
|
- ```rust
|
|
pub fn from_owned_fd_unchecked(owned_fd: OwnedFd) -> io::Result<Sender> { /* ... */ }
|
|
```
|
|
Creates a new `Sender` from an [`OwnedFd`] without checking pipe properties.
|
|
|
|
- ```rust
|
|
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }
|
|
```
|
|
Waits for any of the requested ready states.
|
|
|
|
- ```rust
|
|
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become writable.
|
|
|
|
- ```rust
|
|
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for write readiness.
|
|
|
|
- ```rust
|
|
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write a buffer to the pipe, returning how many bytes were
|
|
|
|
- ```rust
|
|
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write several buffers to the pipe, returning how many bytes
|
|
|
|
- ```rust
|
|
pub fn into_blocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Converts the pipe into an [`OwnedFd`] in blocking mode.
|
|
|
|
- ```rust
|
|
pub fn into_nonblocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Converts the pipe into an [`OwnedFd`] in nonblocking mode.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsFd**
|
|
- ```rust
|
|
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawFd**
|
|
- ```rust
|
|
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWrite**
|
|
- ```rust
|
|
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn is_write_vectored(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWriteExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Receiver`
|
|
|
|
Reading end of a Unix pipe.
|
|
|
|
It can be constructed from a FIFO file with [`OpenOptions::open_receiver`].
|
|
|
|
# Examples
|
|
|
|
Receiving messages from a named pipe in a loop:
|
|
|
|
```no_run
|
|
use tokio::net::unix::pipe;
|
|
use tokio::io::{self, AsyncReadExt};
|
|
|
|
const FIFO_NAME: &str = "path/to/a/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
|
|
loop {
|
|
let mut msg = vec![0; 256];
|
|
match rx.read_exact(&mut msg).await {
|
|
Ok(_) => {
|
|
/* handle the message */
|
|
}
|
|
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
|
|
// Writing end has been closed, we should reopen the pipe.
|
|
rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
|
|
}
|
|
Err(e) => return Err(e.into()),
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
On Linux, you can use a `Receiver` in read-write access mode to implement
|
|
resilient reading from a named pipe. Unlike `Receiver` opened in read-only
|
|
mode, read from a pipe in read-write mode will not fail with `UnexpectedEof`
|
|
when the writing end is closed. This way, a `Receiver` can asynchronously
|
|
wait for the next writer to open the pipe.
|
|
|
|
You should not use functions waiting for EOF such as [`read_to_end`] with
|
|
a `Receiver` in read-write access mode, since it **may wait forever**.
|
|
`Receiver` in this mode also holds an open writing end, which prevents
|
|
receiving EOF.
|
|
|
|
To set the read-write access mode you can use `OpenOptions::read_write`.
|
|
Note that using read-write access mode with FIFO files is not defined by
|
|
the POSIX standard and it is only guaranteed to work on Linux.
|
|
|
|
```ignore
|
|
use tokio::net::unix::pipe;
|
|
use tokio::io::AsyncReadExt;
|
|
# use std::error::Error;
|
|
|
|
const FIFO_NAME: &str = "path/to/a/fifo";
|
|
|
|
# async fn dox() -> Result<(), Box<dyn Error>> {
|
|
let mut rx = pipe::OpenOptions::new()
|
|
.read_write(true)
|
|
.open_receiver(FIFO_NAME)?;
|
|
loop {
|
|
let mut msg = vec![0; 256];
|
|
rx.read_exact(&mut msg).await?;
|
|
/* handle the message */
|
|
}
|
|
# }
|
|
```
|
|
|
|
[`read_to_end`]: crate::io::AsyncReadExt::read_to_end
|
|
|
|
```rust
|
|
pub struct Receiver {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn from_file(file: File) -> io::Result<Receiver> { /* ... */ }
|
|
```
|
|
Creates a new `Receiver` from a [`File`].
|
|
|
|
- ```rust
|
|
pub fn from_owned_fd(owned_fd: OwnedFd) -> io::Result<Receiver> { /* ... */ }
|
|
```
|
|
Creates a new `Receiver` from an [`OwnedFd`].
|
|
|
|
- ```rust
|
|
pub fn from_file_unchecked(file: File) -> io::Result<Receiver> { /* ... */ }
|
|
```
|
|
Creates a new `Receiver` from a [`File`] without checking pipe properties.
|
|
|
|
- ```rust
|
|
pub fn from_owned_fd_unchecked(owned_fd: OwnedFd) -> io::Result<Receiver> { /* ... */ }
|
|
```
|
|
Creates a new `Receiver` from an [`OwnedFd`] without checking pipe properties.
|
|
|
|
- ```rust
|
|
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }
|
|
```
|
|
Waits for any of the requested ready states.
|
|
|
|
- ```rust
|
|
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become readable.
|
|
|
|
- ```rust
|
|
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for read readiness.
|
|
|
|
- ```rust
|
|
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffer, returning how
|
|
|
|
- ```rust
|
|
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffers, returning
|
|
|
|
- ```rust
|
|
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffer, advancing the
|
|
|
|
- ```rust
|
|
pub fn into_blocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Converts the pipe into an [`OwnedFd`] in blocking mode.
|
|
|
|
- ```rust
|
|
pub fn into_nonblocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Converts the pipe into an [`OwnedFd`] in nonblocking mode.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsFd**
|
|
- ```rust
|
|
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawFd**
|
|
- ```rust
|
|
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
|
|
```
|
|
|
|
- **AsyncRead**
|
|
- ```rust
|
|
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncReadExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `pipe`
|
|
|
|
Creates a new anonymous Unix pipe.
|
|
|
|
This function will open a new pipe and associate both pipe ends with the default
|
|
event loop.
|
|
|
|
If you need to create a pipe for communication with a spawned process, you can
|
|
use [`Stdio::piped()`] instead.
|
|
|
|
[`Stdio::piped()`]: std::process::Stdio::piped
|
|
|
|
# Errors
|
|
|
|
If creating a pipe fails, this function will return with the related OS error.
|
|
|
|
# Examples
|
|
|
|
Create a pipe and pass the writing end to a spawned process.
|
|
|
|
```no_run
|
|
use tokio::net::unix::pipe;
|
|
use tokio::process::Command;
|
|
# use tokio::io::AsyncReadExt;
|
|
# use std::error::Error;
|
|
|
|
# async fn dox() -> Result<(), Box<dyn Error>> {
|
|
let (tx, mut rx) = pipe::pipe()?;
|
|
let mut buffer = String::new();
|
|
|
|
let status = Command::new("echo")
|
|
.arg("Hello, world!")
|
|
.stdout(tx.into_blocking_fd()?)
|
|
.status();
|
|
rx.read_to_string(&mut buffer).await?;
|
|
|
|
assert!(status.await?.success());
|
|
assert_eq!(buffer, "Hello, world!\n");
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
# Panics
|
|
|
|
This function panics if it is not called from within a runtime with
|
|
IO enabled.
|
|
|
|
The runtime is usually set implicitly when this function is called
|
|
from a future driven by a tokio runtime, otherwise runtime can be set
|
|
explicitly with [`Runtime::enter`](crate::runtime::Runtime::enter) function.
|
|
|
|
```rust
|
|
pub fn pipe() -> io::Result<(Sender, Receiver)> { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Type Alias `uid_t`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[allow(non_camel_case_types)]")`
|
|
|
|
A type representing user ID.
|
|
|
|
```rust
|
|
pub type uid_t = u32;
|
|
```
|
|
|
|
#### Type Alias `gid_t`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[allow(non_camel_case_types)]")`
|
|
|
|
A type representing group ID.
|
|
|
|
```rust
|
|
pub type gid_t = u32;
|
|
```
|
|
|
|
#### Type Alias `pid_t`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[allow(non_camel_case_types)]")`
|
|
|
|
A type representing process and process group IDs.
|
|
|
|
```rust
|
|
pub type pid_t = i32;
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `ReadHalf`
|
|
|
|
```rust
|
|
pub use split::ReadHalf;
|
|
```
|
|
|
|
#### Re-export `WriteHalf`
|
|
|
|
```rust
|
|
pub use split::WriteHalf;
|
|
```
|
|
|
|
#### Re-export `OwnedReadHalf`
|
|
|
|
```rust
|
|
pub use split_owned::OwnedReadHalf;
|
|
```
|
|
|
|
#### Re-export `OwnedWriteHalf`
|
|
|
|
```rust
|
|
pub use split_owned::OwnedWriteHalf;
|
|
```
|
|
|
|
#### Re-export `ReuniteError`
|
|
|
|
```rust
|
|
pub use split_owned::ReuniteError;
|
|
```
|
|
|
|
#### Re-export `SocketAddr`
|
|
|
|
```rust
|
|
pub use socketaddr::SocketAddr;
|
|
```
|
|
|
|
#### Re-export `UCred`
|
|
|
|
```rust
|
|
pub use ucred::UCred;
|
|
```
|
|
|
|
## Module `windows`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(any(all(doc, docsrs), windows), feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(windows, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(windows, feature = \"net\")))]")`
|
|
|
|
Windows specific network types.
|
|
|
|
```rust
|
|
pub mod windows { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `named_pipe`
|
|
|
|
Tokio support for [Windows named pipes].
|
|
|
|
[Windows named pipes]: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes
|
|
|
|
```rust
|
|
pub mod named_pipe { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `NamedPipeServer`
|
|
|
|
A [Windows named pipe] server.
|
|
|
|
Accepting client connections involves creating a server with
|
|
[`ServerOptions::create`] and waiting for clients to connect using
|
|
[`NamedPipeServer::connect`].
|
|
|
|
To avoid having clients sporadically fail with
|
|
[`std::io::ErrorKind::NotFound`] when they connect to a server, we must
|
|
ensure that at least one server instance is available at all times. This
|
|
means that the typical listen loop for a server is a bit involved, because
|
|
we have to ensure that we never drop a server accidentally while a client
|
|
might connect.
|
|
|
|
So a correctly implemented server looks like this:
|
|
|
|
```no_run
|
|
use std::io;
|
|
use tokio::net::windows::named_pipe::ServerOptions;
|
|
|
|
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-idiomatic-server";
|
|
|
|
# #[tokio::main] async fn main() -> std::io::Result<()> {
|
|
// The first server needs to be constructed early so that clients can
|
|
// be correctly connected. Otherwise calling .wait will cause the client to
|
|
// error.
|
|
//
|
|
// Here we also make use of `first_pipe_instance`, which will ensure that
|
|
// there are no other servers up and running already.
|
|
let mut server = ServerOptions::new()
|
|
.first_pipe_instance(true)
|
|
.create(PIPE_NAME)?;
|
|
|
|
// Spawn the server loop.
|
|
let server = tokio::spawn(async move {
|
|
loop {
|
|
// Wait for a client to connect.
|
|
server.connect().await?;
|
|
let connected_client = server;
|
|
|
|
// Construct the next server to be connected before sending the one
|
|
// we already have of onto a task. This ensures that the server
|
|
// isn't closed (after it's done in the task) before a new one is
|
|
// available. Otherwise the client might error with
|
|
// `io::ErrorKind::NotFound`.
|
|
server = ServerOptions::new().create(PIPE_NAME)?;
|
|
|
|
let client = tokio::spawn(async move {
|
|
/* use the connected client */
|
|
# Ok::<_, std::io::Error>(())
|
|
});
|
|
# if true { break } // needed for type inference to work
|
|
}
|
|
|
|
Ok::<_, io::Error>(())
|
|
});
|
|
|
|
/* do something else not server related here */
|
|
# Ok(()) }
|
|
```
|
|
|
|
[Windows named pipe]: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes
|
|
|
|
```rust
|
|
pub struct NamedPipeServer {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub unsafe fn from_raw_handle(handle: RawHandle) -> io::Result<Self> { /* ... */ }
|
|
```
|
|
Constructs a new named pipe server from the specified raw handle.
|
|
|
|
- ```rust
|
|
pub fn info(self: &Self) -> io::Result<PipeInfo> { /* ... */ }
|
|
```
|
|
Retrieves information about the named pipe the server is associated
|
|
|
|
- ```rust
|
|
pub async fn connect(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Enables a named pipe server process to wait for a client process to
|
|
|
|
- ```rust
|
|
pub fn disconnect(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Disconnects the server end of a named pipe instance from a client
|
|
|
|
- ```rust
|
|
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }
|
|
```
|
|
Waits for any of the requested ready states.
|
|
|
|
- ```rust
|
|
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become readable.
|
|
|
|
- ```rust
|
|
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for read readiness.
|
|
|
|
- ```rust
|
|
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffer, returning how
|
|
|
|
- ```rust
|
|
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffers, returning
|
|
|
|
- ```rust
|
|
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the stream into the provided buffer, advancing the
|
|
|
|
- ```rust
|
|
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become writable.
|
|
|
|
- ```rust
|
|
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for write readiness.
|
|
|
|
- ```rust
|
|
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write a buffer to the pipe, returning how many bytes were
|
|
|
|
- ```rust
|
|
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write several buffers to the pipe, returning how many bytes
|
|
|
|
- ```rust
|
|
pub fn try_io<R, /* synthetic */ impl FnOnce() -> io::Result<R>: FnOnce() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnOnce() -> io::Result<R>) -> io::Result<R> { /* ... */ }
|
|
```
|
|
Tries to read or write from the pipe using a user-provided IO operation.
|
|
|
|
- ```rust
|
|
pub async fn async_io<R, /* synthetic */ impl FnMut() -> io::Result<R>: FnMut() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnMut() -> io::Result<R>) -> io::Result<R> { /* ... */ }
|
|
```
|
|
Reads or writes from the pipe using a user-provided IO operation.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsHandle**
|
|
- ```rust
|
|
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawHandle**
|
|
- ```rust
|
|
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
|
|
```
|
|
|
|
- **AsyncRead**
|
|
- ```rust
|
|
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncReadExt**
|
|
- **AsyncWrite**
|
|
- ```rust
|
|
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWriteExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `NamedPipeClient`
|
|
|
|
A [Windows named pipe] client.
|
|
|
|
Constructed using [`ClientOptions::open`].
|
|
|
|
Connecting a client correctly involves a few steps. When connecting through
|
|
[`ClientOptions::open`], it might error indicating one of two things:
|
|
|
|
* [`std::io::ErrorKind::NotFound`] - There is no server available.
|
|
* [`ERROR_PIPE_BUSY`] - There is a server available, but it is busy. Sleep
|
|
for a while and try again.
|
|
|
|
So a correctly implemented client looks like this:
|
|
|
|
```no_run
|
|
use std::time::Duration;
|
|
use tokio::net::windows::named_pipe::ClientOptions;
|
|
use tokio::time;
|
|
use windows_sys::Win32::Foundation::ERROR_PIPE_BUSY;
|
|
|
|
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-idiomatic-client";
|
|
|
|
# #[tokio::main] async fn main() -> std::io::Result<()> {
|
|
let client = loop {
|
|
match ClientOptions::new().open(PIPE_NAME) {
|
|
Ok(client) => break client,
|
|
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
|
|
Err(e) => return Err(e),
|
|
}
|
|
|
|
time::sleep(Duration::from_millis(50)).await;
|
|
};
|
|
|
|
/* use the connected client */
|
|
# Ok(()) }
|
|
```
|
|
|
|
[`ERROR_PIPE_BUSY`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/Foundation/constant.ERROR_PIPE_BUSY.html
|
|
[Windows named pipe]: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes
|
|
|
|
```rust
|
|
pub struct NamedPipeClient {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub unsafe fn from_raw_handle(handle: RawHandle) -> io::Result<Self> { /* ... */ }
|
|
```
|
|
Constructs a new named pipe client from the specified raw handle.
|
|
|
|
- ```rust
|
|
pub fn info(self: &Self) -> io::Result<PipeInfo> { /* ... */ }
|
|
```
|
|
Retrieves information about the named pipe the client is associated
|
|
|
|
- ```rust
|
|
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }
|
|
```
|
|
Waits for any of the requested ready states.
|
|
|
|
- ```rust
|
|
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become readable.
|
|
|
|
- ```rust
|
|
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for read readiness.
|
|
|
|
- ```rust
|
|
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffer, returning how
|
|
|
|
- ```rust
|
|
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the pipe into the provided buffers, returning
|
|
|
|
- ```rust
|
|
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to read data from the stream into the provided buffer, advancing the
|
|
|
|
- ```rust
|
|
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Waits for the pipe to become writable.
|
|
|
|
- ```rust
|
|
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
Polls for write readiness.
|
|
|
|
- ```rust
|
|
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write a buffer to the pipe, returning how many bytes were
|
|
|
|
- ```rust
|
|
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }
|
|
```
|
|
Tries to write several buffers to the pipe, returning how many bytes
|
|
|
|
- ```rust
|
|
pub fn try_io<R, /* synthetic */ impl FnOnce() -> io::Result<R>: FnOnce() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnOnce() -> io::Result<R>) -> io::Result<R> { /* ... */ }
|
|
```
|
|
Tries to read or write from the pipe using a user-provided IO operation.
|
|
|
|
- ```rust
|
|
pub async fn async_io<R, /* synthetic */ impl FnMut() -> io::Result<R>: FnMut() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnMut() -> io::Result<R>) -> io::Result<R> { /* ... */ }
|
|
```
|
|
Reads or writes from the pipe using a user-provided IO operation.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsHandle**
|
|
- ```rust
|
|
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawHandle**
|
|
- ```rust
|
|
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
|
|
```
|
|
|
|
- **AsyncRead**
|
|
- ```rust
|
|
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncReadExt**
|
|
- **AsyncWrite**
|
|
- ```rust
|
|
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWriteExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `ServerOptions`
|
|
|
|
A builder structure for construct a named pipe with named pipe-specific
|
|
options. This is required to use for named pipe servers who wants to modify
|
|
pipe-related options.
|
|
|
|
See [`ServerOptions::create`].
|
|
|
|
```rust
|
|
pub struct ServerOptions {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new() -> ServerOptions { /* ... */ }
|
|
```
|
|
Creates a new named pipe builder with the default settings.
|
|
|
|
- ```rust
|
|
pub fn pipe_mode(self: &mut Self, pipe_mode: PipeMode) -> &mut Self { /* ... */ }
|
|
```
|
|
The pipe mode.
|
|
|
|
- ```rust
|
|
pub fn access_inbound(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
The flow of data in the pipe goes from client to server only.
|
|
|
|
- ```rust
|
|
pub fn access_outbound(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
The flow of data in the pipe goes from server to client only.
|
|
|
|
- ```rust
|
|
pub fn first_pipe_instance(self: &mut Self, first: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
If you attempt to create multiple instances of a pipe with this flag
|
|
|
|
- ```rust
|
|
pub fn write_dac(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Requests permission to modify the pipe's discretionary access control list.
|
|
|
|
- ```rust
|
|
pub fn write_owner(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Requests permission to modify the pipe's owner.
|
|
|
|
- ```rust
|
|
pub fn access_system_security(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Requests permission to modify the pipe's system access control list.
|
|
|
|
- ```rust
|
|
pub fn reject_remote_clients(self: &mut Self, reject: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
Indicates whether this server can accept remote clients or not. Remote
|
|
|
|
- ```rust
|
|
pub fn max_instances(self: &mut Self, instances: usize) -> &mut Self { /* ... */ }
|
|
```
|
|
The maximum number of instances that can be created for this pipe. The
|
|
|
|
- ```rust
|
|
pub fn out_buffer_size(self: &mut Self, buffer: u32) -> &mut Self { /* ... */ }
|
|
```
|
|
The number of bytes to reserve for the output buffer.
|
|
|
|
- ```rust
|
|
pub fn in_buffer_size(self: &mut Self, buffer: u32) -> &mut Self { /* ... */ }
|
|
```
|
|
The number of bytes to reserve for the input buffer.
|
|
|
|
- ```rust
|
|
pub fn create</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>) -> io::Result<NamedPipeServer> { /* ... */ }
|
|
```
|
|
Creates the named pipe identified by `addr` for use as a server.
|
|
|
|
- ```rust
|
|
pub unsafe fn create_with_security_attributes_raw</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>, attrs: *mut c_void) -> io::Result<NamedPipeServer> { /* ... */ }
|
|
```
|
|
Creates the named pipe identified by `addr` for use as a server.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> ServerOptions { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `ClientOptions`
|
|
|
|
A builder suitable for building and interacting with named pipes from the
|
|
client side.
|
|
|
|
See [`ClientOptions::open`].
|
|
|
|
```rust
|
|
pub struct ClientOptions {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new() -> Self { /* ... */ }
|
|
```
|
|
Creates a new named pipe builder with the default settings.
|
|
|
|
- ```rust
|
|
pub fn read(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
If the client supports reading data. This is enabled by default.
|
|
|
|
- ```rust
|
|
pub fn write(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }
|
|
```
|
|
If the created pipe supports writing data. This is enabled by default.
|
|
|
|
- ```rust
|
|
pub fn security_qos_flags(self: &mut Self, flags: u32) -> &mut Self { /* ... */ }
|
|
```
|
|
Sets qos flags which are combined with other flags and attributes in the
|
|
|
|
- ```rust
|
|
pub fn pipe_mode(self: &mut Self, pipe_mode: PipeMode) -> &mut Self { /* ... */ }
|
|
```
|
|
The pipe mode.
|
|
|
|
- ```rust
|
|
pub fn open</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>) -> io::Result<NamedPipeClient> { /* ... */ }
|
|
```
|
|
Opens the named pipe identified by `addr`.
|
|
|
|
- ```rust
|
|
pub unsafe fn open_with_security_attributes_raw</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>, attrs: *mut c_void) -> io::Result<NamedPipeClient> { /* ... */ }
|
|
```
|
|
Opens the named pipe identified by `addr`.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> ClientOptions { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `PipeMode`
|
|
|
|
**Attributes:**
|
|
|
|
- `NonExhaustive`
|
|
|
|
The pipe mode of a named pipe.
|
|
|
|
Set through [`ServerOptions::pipe_mode`].
|
|
|
|
```rust
|
|
pub enum PipeMode {
|
|
Byte,
|
|
Message,
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Byte`
|
|
|
|
Data is written to the pipe as a stream of bytes. The pipe does not
|
|
distinguish bytes written during different write operations.
|
|
|
|
Corresponds to [`PIPE_TYPE_BYTE`].
|
|
|
|
[`PIPE_TYPE_BYTE`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Pipes/constant.PIPE_TYPE_BYTE.html
|
|
|
|
###### `Message`
|
|
|
|
Data is written to the pipe as a stream of messages. The pipe treats the
|
|
bytes written during each write operation as a message unit. Any reading
|
|
on a named pipe returns [`ERROR_MORE_DATA`] when a message is not read
|
|
completely.
|
|
|
|
Corresponds to [`PIPE_TYPE_MESSAGE`].
|
|
|
|
[`ERROR_MORE_DATA`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/Foundation/constant.ERROR_MORE_DATA.html
|
|
[`PIPE_TYPE_MESSAGE`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Pipes/constant.PIPE_TYPE_MESSAGE.html
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> PipeMode { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Hash**
|
|
- ```rust
|
|
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &PipeMode) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `PipeEnd`
|
|
|
|
**Attributes:**
|
|
|
|
- `NonExhaustive`
|
|
|
|
Indicates the end of a named pipe.
|
|
|
|
```rust
|
|
pub enum PipeEnd {
|
|
Client,
|
|
Server,
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Client`
|
|
|
|
The named pipe refers to the client end of a named pipe instance.
|
|
|
|
Corresponds to [`PIPE_CLIENT_END`].
|
|
|
|
[`PIPE_CLIENT_END`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Pipes/constant.PIPE_CLIENT_END.html
|
|
|
|
###### `Server`
|
|
|
|
The named pipe refers to the server end of a named pipe instance.
|
|
|
|
Corresponds to [`PIPE_SERVER_END`].
|
|
|
|
[`PIPE_SERVER_END`]: https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Pipes/constant.PIPE_SERVER_END.html
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> PipeEnd { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Hash**
|
|
- ```rust
|
|
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &PipeEnd) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `PipeInfo`
|
|
|
|
**Attributes:**
|
|
|
|
- `NonExhaustive`
|
|
|
|
Information about a named pipe.
|
|
|
|
Constructed through [`NamedPipeServer::info`] or [`NamedPipeClient::info`].
|
|
|
|
```rust
|
|
pub struct PipeInfo {
|
|
pub mode: PipeMode,
|
|
pub end: PipeEnd,
|
|
pub max_instances: u32,
|
|
pub out_buffer_size: u32,
|
|
pub in_buffer_size: u32,
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| `mode` | `PipeMode` | Indicates the mode of a named pipe. |
|
|
| `end` | `PipeEnd` | Indicates the end of a named pipe. |
|
|
| `max_instances` | `u32` | The maximum number of instances that can be created for this pipe. |
|
|
| `out_buffer_size` | `u32` | The number of bytes to reserve for the output buffer. |
|
|
| `in_buffer_size` | `u32` | The number of bytes to reserve for the input buffer. |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> PipeInfo { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Re-exports
|
|
|
|
#### Re-export `ToSocketAddrs`
|
|
|
|
```rust
|
|
pub use addr::ToSocketAddrs;
|
|
```
|
|
|
|
#### Re-export `lookup_host`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"net\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"net\"))]")`
|
|
|
|
```rust
|
|
pub use lookup_host::lookup_host;
|
|
```
|
|
|
|
#### Re-export `TcpListener`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"net\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"net\"))]")`
|
|
|
|
```rust
|
|
pub use tcp::listener::TcpListener;
|
|
```
|
|
|
|
#### Re-export `TcpStream`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"net\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"net\"))]")`
|
|
|
|
```rust
|
|
pub use tcp::stream::TcpStream;
|
|
```
|
|
|
|
#### Re-export `TcpSocket`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(not(target_os = \"wasi\"))]")`
|
|
|
|
```rust
|
|
pub use tcp::socket::TcpSocket;
|
|
```
|
|
|
|
#### Re-export `UdpSocket`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(not(target_os = \"wasi\"))]")`
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use udp::UdpSocket;
|
|
```
|
|
|
|
#### Re-export `UnixDatagram`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
```rust
|
|
pub use unix::datagram::socket::UnixDatagram;
|
|
```
|
|
|
|
#### Re-export `UnixListener`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
```rust
|
|
pub use unix::listener::UnixListener;
|
|
```
|
|
|
|
#### Re-export `UnixStream`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
```rust
|
|
pub use unix::stream::UnixStream;
|
|
```
|
|
|
|
#### Re-export `UnixSocket`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(unix, feature = \"net\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"net\")))]")`
|
|
|
|
```rust
|
|
pub use unix::socket::UnixSocket;
|
|
```
|
|
|
|
## Module `process`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"process\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"process\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"process\"))]")`
|
|
- `Other("#[<cfg>(not(loom))]")`
|
|
- `Other("#[<cfg>(not(target_os = \"wasi\"))]")`
|
|
|
|
An implementation of asynchronous process management for Tokio.
|
|
|
|
This module provides a [`Command`] struct that imitates the interface of the
|
|
[`std::process::Command`] type in the standard library, but provides asynchronous versions of
|
|
functions that create processes. These functions (`spawn`, `status`, `output` and their
|
|
variants) return "future aware" types that interoperate with Tokio. The asynchronous process
|
|
support is provided through signal handling on Unix and system APIs on Windows.
|
|
|
|
[`std::process::Command`]: std::process::Command
|
|
|
|
# Examples
|
|
|
|
Here's an example program which will spawn `echo hello world` and then wait
|
|
for it complete.
|
|
|
|
```no_run
|
|
use tokio::process::Command;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// The usage is similar as with the standard library's `Command` type
|
|
let mut child = Command::new("echo")
|
|
.arg("hello")
|
|
.arg("world")
|
|
.spawn()
|
|
.expect("failed to spawn");
|
|
|
|
// Await until the command completes
|
|
let status = child.wait().await?;
|
|
println!("the command exited with: {}", status);
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
Next, let's take a look at an example where we not only spawn `echo hello
|
|
world` but we also capture its output.
|
|
|
|
```no_run
|
|
use tokio::process::Command;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Like above, but use `output` which returns a future instead of
|
|
// immediately returning the `Child`.
|
|
let output = Command::new("echo").arg("hello").arg("world")
|
|
.output();
|
|
|
|
let output = output.await?;
|
|
|
|
assert!(output.status.success());
|
|
assert_eq!(output.stdout, b"hello world\n");
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
We can also read input line by line.
|
|
|
|
```no_run
|
|
use tokio::io::{BufReader, AsyncBufReadExt};
|
|
use tokio::process::Command;
|
|
|
|
use std::process::Stdio;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut cmd = Command::new("cat");
|
|
|
|
// Specify that we want the command's standard output piped back to us.
|
|
// By default, standard input/output/error will be inherited from the
|
|
// current process (for example, this means that standard input will
|
|
// come from the keyboard and standard output/error will go directly to
|
|
// the terminal if this process is invoked from the command line).
|
|
cmd.stdout(Stdio::piped());
|
|
|
|
let mut child = cmd.spawn()
|
|
.expect("failed to spawn command");
|
|
|
|
let stdout = child.stdout.take()
|
|
.expect("child did not have a handle to stdout");
|
|
|
|
let mut reader = BufReader::new(stdout).lines();
|
|
|
|
// Ensure the child process is spawned in the runtime so it can
|
|
// make progress on its own while we await for any output.
|
|
tokio::spawn(async move {
|
|
let status = child.wait().await
|
|
.expect("child process encountered an error");
|
|
|
|
println!("child status was: {}", status);
|
|
});
|
|
|
|
while let Some(line) = reader.next_line().await? {
|
|
println!("Line: {}", line);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
Here is another example using `sort` writing into the child process
|
|
standard input, capturing the output of the sorted text.
|
|
|
|
```no_run
|
|
use tokio::io::AsyncWriteExt;
|
|
use tokio::process::Command;
|
|
|
|
use std::process::Stdio;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut cmd = Command::new("sort");
|
|
|
|
// Specifying that we want pipe both the output and the input.
|
|
// Similarly to capturing the output, by configuring the pipe
|
|
// to stdin it can now be used as an asynchronous writer.
|
|
cmd.stdout(Stdio::piped());
|
|
cmd.stdin(Stdio::piped());
|
|
|
|
let mut child = cmd.spawn().expect("failed to spawn command");
|
|
|
|
// These are the animals we want to sort
|
|
let animals: &[&str] = &["dog", "bird", "frog", "cat", "fish"];
|
|
|
|
let mut stdin = child
|
|
.stdin
|
|
.take()
|
|
.expect("child did not have a handle to stdin");
|
|
|
|
// Write our animals to the child process
|
|
// Note that the behavior of `sort` is to buffer _all input_ before writing any output.
|
|
// In the general sense, it is recommended to write to the child in a separate task as
|
|
// awaiting its exit (or output) to avoid deadlocks (for example, the child tries to write
|
|
// some output but gets stuck waiting on the parent to read from it, meanwhile the parent
|
|
// is stuck waiting to write its input completely before reading the output).
|
|
stdin
|
|
.write(animals.join("\n").as_bytes())
|
|
.await
|
|
.expect("could not write to stdin");
|
|
|
|
// We drop the handle here which signals EOF to the child process.
|
|
// This tells the child process that it there is no more data on the pipe.
|
|
drop(stdin);
|
|
|
|
let op = child.wait_with_output().await?;
|
|
|
|
// Results should come back in sorted order
|
|
assert_eq!(op.stdout, "bird\ncat\ndog\nfish\nfrog\n".as_bytes());
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
With some coordination, we can also pipe the output of one command into
|
|
another.
|
|
|
|
```no_run
|
|
use tokio::join;
|
|
use tokio::process::Command;
|
|
use std::process::Stdio;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut echo = Command::new("echo")
|
|
.arg("hello world!")
|
|
.stdout(Stdio::piped())
|
|
.spawn()
|
|
.expect("failed to spawn echo");
|
|
|
|
let tr_stdin: Stdio = echo
|
|
.stdout
|
|
.take()
|
|
.unwrap()
|
|
.try_into()
|
|
.expect("failed to convert to Stdio");
|
|
|
|
let tr = Command::new("tr")
|
|
.arg("a-z")
|
|
.arg("A-Z")
|
|
.stdin(tr_stdin)
|
|
.stdout(Stdio::piped())
|
|
.spawn()
|
|
.expect("failed to spawn tr");
|
|
|
|
let (echo_result, tr_output) = join!(echo.wait(), tr.wait_with_output());
|
|
|
|
assert!(echo_result.unwrap().success());
|
|
|
|
let tr_output = tr_output.expect("failed to await tr");
|
|
assert!(tr_output.status.success());
|
|
|
|
assert_eq!(tr_output.stdout, b"HELLO WORLD!\n");
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
# Caveats
|
|
|
|
## Dropping/Cancellation
|
|
|
|
Similar to the behavior to the standard library, and unlike the futures
|
|
paradigm of dropping-implies-cancellation, a spawned process will, by
|
|
default, continue to execute even after the `Child` handle has been dropped.
|
|
|
|
The [`Command::kill_on_drop`] method can be used to modify this behavior
|
|
and kill the child process if the `Child` wrapper is dropped before it
|
|
has exited.
|
|
|
|
## Unix Processes
|
|
|
|
On Unix platforms processes must be "reaped" by their parent process after
|
|
they have exited in order to release all OS resources. A child process which
|
|
has exited, but has not yet been reaped by its parent is considered a "zombie"
|
|
process. Such processes continue to count against limits imposed by the system,
|
|
and having too many zombie processes present can prevent additional processes
|
|
from being spawned.
|
|
|
|
The tokio runtime will, on a best-effort basis, attempt to reap and clean up
|
|
any process which it has spawned. No additional guarantees are made with regard to
|
|
how quickly or how often this procedure will take place.
|
|
|
|
It is recommended to avoid dropping a [`Child`] process handle before it has been
|
|
fully `await`ed if stricter cleanup guarantees are required.
|
|
|
|
[`Command`]: crate::process::Command
|
|
[`Command::kill_on_drop`]: crate::process::Command::kill_on_drop
|
|
[`Child`]: crate::process::Child
|
|
|
|
```rust
|
|
pub mod process { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `Command`
|
|
|
|
This structure mimics the API of [`std::process::Command`] found in the standard library, but
|
|
replaces functions that create a process with an asynchronous variant. The main provided
|
|
asynchronous functions are [spawn](Command::spawn), [status](Command::status), and
|
|
[output](Command::output).
|
|
|
|
`Command` uses asynchronous versions of some `std` types (for example [`Child`]).
|
|
|
|
[`std::process::Command`]: std::process::Command
|
|
[`Child`]: struct@Child
|
|
|
|
```rust
|
|
pub struct Command {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new<S: AsRef<OsStr>>(program: S) -> Command { /* ... */ }
|
|
```
|
|
Constructs a new `Command` for launching the program at
|
|
|
|
- ```rust
|
|
pub fn as_std(self: &Self) -> &StdCommand { /* ... */ }
|
|
```
|
|
Cheaply convert to a `&std::process::Command` for places where the type from the standard
|
|
|
|
- ```rust
|
|
pub fn as_std_mut(self: &mut Self) -> &mut StdCommand { /* ... */ }
|
|
```
|
|
Cheaply convert to a `&mut std::process::Command` for places where the type from the
|
|
|
|
- ```rust
|
|
pub fn into_std(self: Self) -> StdCommand { /* ... */ }
|
|
```
|
|
Cheaply convert into a `std::process::Command`.
|
|
|
|
- ```rust
|
|
pub fn arg<S: AsRef<OsStr>>(self: &mut Self, arg: S) -> &mut Command { /* ... */ }
|
|
```
|
|
Adds an argument to pass to the program.
|
|
|
|
- ```rust
|
|
pub fn args<I, S>(self: &mut Self, args: I) -> &mut Command
|
|
where
|
|
I: IntoIterator<Item = S>,
|
|
S: AsRef<OsStr> { /* ... */ }
|
|
```
|
|
Adds multiple arguments to pass to the program.
|
|
|
|
- ```rust
|
|
pub fn raw_arg<S: AsRef<OsStr>>(self: &mut Self, text_to_append_as_is: S) -> &mut Command { /* ... */ }
|
|
```
|
|
Append literal text to the command line without any quoting or escaping.
|
|
|
|
- ```rust
|
|
pub fn env<K, V>(self: &mut Self, key: K, val: V) -> &mut Command
|
|
where
|
|
K: AsRef<OsStr>,
|
|
V: AsRef<OsStr> { /* ... */ }
|
|
```
|
|
Inserts or updates an environment variable mapping.
|
|
|
|
- ```rust
|
|
pub fn envs<I, K, V>(self: &mut Self, vars: I) -> &mut Command
|
|
where
|
|
I: IntoIterator<Item = (K, V)>,
|
|
K: AsRef<OsStr>,
|
|
V: AsRef<OsStr> { /* ... */ }
|
|
```
|
|
Adds or updates multiple environment variable mappings.
|
|
|
|
- ```rust
|
|
pub fn env_remove<K: AsRef<OsStr>>(self: &mut Self, key: K) -> &mut Command { /* ... */ }
|
|
```
|
|
Removes an environment variable mapping.
|
|
|
|
- ```rust
|
|
pub fn env_clear(self: &mut Self) -> &mut Command { /* ... */ }
|
|
```
|
|
Clears the entire environment map for the child process.
|
|
|
|
- ```rust
|
|
pub fn current_dir<P: AsRef<Path>>(self: &mut Self, dir: P) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets the working directory for the child process.
|
|
|
|
- ```rust
|
|
pub fn stdin<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets configuration for the child process's standard input (stdin) handle.
|
|
|
|
- ```rust
|
|
pub fn stdout<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets configuration for the child process's standard output (stdout) handle.
|
|
|
|
- ```rust
|
|
pub fn stderr<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets configuration for the child process's standard error (stderr) handle.
|
|
|
|
- ```rust
|
|
pub fn kill_on_drop(self: &mut Self, kill_on_drop: bool) -> &mut Command { /* ... */ }
|
|
```
|
|
Controls whether a `kill` operation should be invoked on a spawned child
|
|
|
|
- ```rust
|
|
pub fn creation_flags(self: &mut Self, flags: u32) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets the [process creation flags][1] to be passed to `CreateProcess`.
|
|
|
|
- ```rust
|
|
pub fn uid(self: &mut Self, id: u32) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets the child process's user ID. This translates to a
|
|
|
|
- ```rust
|
|
pub fn gid(self: &mut Self, id: u32) -> &mut Command { /* ... */ }
|
|
```
|
|
Similar to `uid` but sets the group ID of the child process. This has
|
|
|
|
- ```rust
|
|
pub fn arg0<S>(self: &mut Self, arg: S) -> &mut Command
|
|
where
|
|
S: AsRef<OsStr> { /* ... */ }
|
|
```
|
|
Sets executable argument.
|
|
|
|
- ```rust
|
|
pub unsafe fn pre_exec<F>(self: &mut Self, f: F) -> &mut Command
|
|
where
|
|
F: FnMut() -> io::Result<()> + Send + Sync + ''static { /* ... */ }
|
|
```
|
|
Schedules a closure to be run just before the `exec` function is
|
|
|
|
- ```rust
|
|
pub fn process_group(self: &mut Self, pgroup: i32) -> &mut Command { /* ... */ }
|
|
```
|
|
Sets the process group ID (PGID) of the child process. Equivalent to a
|
|
|
|
- ```rust
|
|
pub fn spawn(self: &mut Self) -> io::Result<Child> { /* ... */ }
|
|
```
|
|
Executes the command as a child process, returning a handle to it.
|
|
|
|
- ```rust
|
|
pub fn spawn_with</* synthetic */ impl FnOnce(&mut StdCommand) -> io::Result<StdChild>: FnOnce(&mut StdCommand) -> io::Result<StdChild>>(self: &mut Self, with: impl FnOnce(&mut StdCommand) -> io::Result<StdChild>) -> io::Result<Child> { /* ... */ }
|
|
```
|
|
Executes the command as a child process with a custom spawning function,
|
|
|
|
- ```rust
|
|
pub fn status(self: &mut Self) -> impl Future<Output = io::Result<ExitStatus>> { /* ... */ }
|
|
```
|
|
Executes the command as a child process, waiting for it to finish and
|
|
|
|
- ```rust
|
|
pub fn output(self: &mut Self) -> impl Future<Output = io::Result<Output>> { /* ... */ }
|
|
```
|
|
Executes the command as a child process, waiting for it to finish and
|
|
|
|
- ```rust
|
|
pub fn get_kill_on_drop(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns the boolean value that was previously set by [`Command::kill_on_drop`].
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- ```rust
|
|
fn from(std: StdCommand) -> Command { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Child`
|
|
|
|
Representation of a child process spawned onto an event loop.
|
|
|
|
# Caveats
|
|
Similar to the behavior to the standard library, and unlike the futures
|
|
paradigm of dropping-implies-cancellation, a spawned process will, by
|
|
default, continue to execute even after the `Child` handle has been dropped.
|
|
|
|
The `Command::kill_on_drop` method can be used to modify this behavior
|
|
and kill the child process if the `Child` wrapper is dropped before it
|
|
has exited.
|
|
|
|
```rust
|
|
pub struct Child {
|
|
pub stdin: Option<ChildStdin>,
|
|
pub stdout: Option<ChildStdout>,
|
|
pub stderr: Option<ChildStderr>,
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| `stdin` | `Option<ChildStdin>` | The handle for writing to the child's standard input (stdin), if it has<br>been captured. To avoid partially moving the `child` and thus blocking<br>yourself from calling functions on `child` while using `stdin`, you might<br>find it helpful to do:<br><br>```no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stdin = child.stdin.take().unwrap();<br>``` |
|
|
| `stdout` | `Option<ChildStdout>` | The handle for reading from the child's standard output (stdout), if it<br>has been captured. You might find it helpful to do<br><br>```no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stdout = child.stdout.take().unwrap();<br>```<br><br>to avoid partially moving the `child` and thus blocking yourself from calling<br>functions on `child` while using `stdout`. |
|
|
| `stderr` | `Option<ChildStderr>` | The handle for reading from the child's standard error (stderr), if it<br>has been captured. You might find it helpful to do<br><br>```no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stderr = child.stderr.take().unwrap();<br>```<br><br>to avoid partially moving the `child` and thus blocking yourself from calling<br>functions on `child` while using `stderr`. |
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn id(self: &Self) -> Option<u32> { /* ... */ }
|
|
```
|
|
Returns the OS-assigned process identifier associated with this child
|
|
|
|
- ```rust
|
|
pub fn raw_handle(self: &Self) -> Option<RawHandle> { /* ... */ }
|
|
```
|
|
Extracts the raw handle of the process associated with this child while
|
|
|
|
- ```rust
|
|
pub fn start_kill(self: &mut Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Attempts to force the child to exit, but does not wait for the request
|
|
|
|
- ```rust
|
|
pub async fn kill(self: &mut Self) -> io::Result<()> { /* ... */ }
|
|
```
|
|
Forces the child to exit.
|
|
|
|
- ```rust
|
|
pub async fn wait(self: &mut Self) -> io::Result<ExitStatus> { /* ... */ }
|
|
```
|
|
Waits for the child to exit completely, returning the status that it
|
|
|
|
- ```rust
|
|
pub fn try_wait(self: &mut Self) -> io::Result<Option<ExitStatus>> { /* ... */ }
|
|
```
|
|
Attempts to collect the exit status of the child if it has already
|
|
|
|
- ```rust
|
|
pub async fn wait_with_output(self: Self) -> io::Result<Output> { /* ... */ }
|
|
```
|
|
Returns a future that will resolve to an `Output`, containing the exit
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `ChildStdin`
|
|
|
|
The standard input stream for spawned children.
|
|
|
|
This type implements the `AsyncWrite` trait to pass data to the stdin
|
|
handle of a child process asynchronously.
|
|
|
|
```rust
|
|
pub struct ChildStdin {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedFd`].
|
|
|
|
- ```rust
|
|
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedHandle`].
|
|
|
|
- ```rust
|
|
pub fn from_std(inner: std::process::ChildStdin) -> io::Result<Self> { /* ... */ }
|
|
```
|
|
Creates an asynchronous `ChildStdin` from a synchronous one.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsFd**
|
|
- ```rust
|
|
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsHandle**
|
|
- ```rust
|
|
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawFd**
|
|
- ```rust
|
|
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
|
|
```
|
|
|
|
- **AsRawHandle**
|
|
- ```rust
|
|
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWrite**
|
|
- ```rust
|
|
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<Result<usize, io::Error>> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn is_write_vectored(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **AsyncWriteExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `ChildStdout`
|
|
|
|
The standard output stream for spawned children.
|
|
|
|
This type implements the `AsyncRead` trait to read data from the stdout
|
|
handle of a child process asynchronously.
|
|
|
|
```rust
|
|
pub struct ChildStdout {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedFd`].
|
|
|
|
- ```rust
|
|
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedHandle`].
|
|
|
|
- ```rust
|
|
pub fn from_std(inner: std::process::ChildStdout) -> io::Result<Self> { /* ... */ }
|
|
```
|
|
Creates an asynchronous `ChildStdout` from a synchronous one.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsFd**
|
|
- ```rust
|
|
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsHandle**
|
|
- ```rust
|
|
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawFd**
|
|
- ```rust
|
|
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
|
|
```
|
|
|
|
- **AsRawHandle**
|
|
- ```rust
|
|
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
|
|
```
|
|
|
|
- **AsyncRead**
|
|
- ```rust
|
|
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncReadExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `ChildStderr`
|
|
|
|
The standard error stream for spawned children.
|
|
|
|
This type implements the `AsyncRead` trait to read data from the stderr
|
|
handle of a child process asynchronously.
|
|
|
|
```rust
|
|
pub struct ChildStderr {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedFd`].
|
|
|
|
- ```rust
|
|
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }
|
|
```
|
|
Convert into [`OwnedHandle`].
|
|
|
|
- ```rust
|
|
pub fn from_std(inner: std::process::ChildStderr) -> io::Result<Self> { /* ... */ }
|
|
```
|
|
Creates an asynchronous `ChildStderr` from a synchronous one.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **AsFd**
|
|
- ```rust
|
|
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsHandle**
|
|
- ```rust
|
|
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
|
|
```
|
|
|
|
- **AsRawFd**
|
|
- ```rust
|
|
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
|
|
```
|
|
|
|
- **AsRawHandle**
|
|
- ```rust
|
|
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
|
|
```
|
|
|
|
- **AsyncRead**
|
|
- ```rust
|
|
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
|
|
```
|
|
|
|
- **AsyncReadExt**
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
## Module `runtime`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
The Tokio runtime.
|
|
|
|
Unlike other Rust programs, asynchronous applications require runtime
|
|
support. In particular, the following runtime services are necessary:
|
|
|
|
* An **I/O event loop**, called the driver, which drives I/O resources and
|
|
dispatches I/O events to tasks that depend on them.
|
|
* A **scheduler** to execute [tasks] that use these I/O resources.
|
|
* A **timer** for scheduling work to run after a set period of time.
|
|
|
|
Tokio's [`Runtime`] bundles all of these services as a single type, allowing
|
|
them to be started, shut down, and configured together. However, often it is
|
|
not required to configure a [`Runtime`] manually, and a user may just use the
|
|
[`tokio::main`] attribute macro, which creates a [`Runtime`] under the hood.
|
|
|
|
# Choose your runtime
|
|
|
|
Here is the rules of thumb to choose the right runtime for your application.
|
|
|
|
```plaintext
|
|
+------------------------------------------------------+
|
|
| Do you want work-stealing or multi-thread scheduler? |
|
|
+------------------------------------------------------+
|
|
| Yes | No
|
|
| |
|
|
| |
|
|
v |
|
|
+------------------------+ |
|
|
| Multi-threaded Runtime | |
|
|
+------------------------+ |
|
|
|
|
|
V
|
|
+--------------------------------+
|
|
| Do you execute `!Send` Future? |
|
|
+--------------------------------+
|
|
| Yes | No
|
|
| |
|
|
V |
|
|
+--------------------------+ |
|
|
| Local Runtime (unstable) | |
|
|
+--------------------------+ |
|
|
|
|
|
v
|
|
+------------------------+
|
|
| Current-thread Runtime |
|
|
+------------------------+
|
|
```
|
|
|
|
The above decision tree is not exhaustive. there are other factors that
|
|
may influence your decision.
|
|
|
|
## Bridging with sync code
|
|
|
|
See <https://tokio.rs/tokio/topics/bridging> for details.
|
|
|
|
## NUMA awareness
|
|
|
|
The tokio runtime is not NUMA (Non-Uniform Memory Access) aware.
|
|
You may want to start multiple runtimes instead of a single runtime
|
|
for better performance on NUMA systems.
|
|
|
|
# Usage
|
|
|
|
When no fine tuning is required, the [`tokio::main`] attribute macro can be
|
|
used.
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::net::TcpListener;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let listener = TcpListener::bind("127.0.0.1:8080").await?;
|
|
|
|
loop {
|
|
let (mut socket, _) = listener.accept().await?;
|
|
|
|
tokio::spawn(async move {
|
|
let mut buf = [0; 1024];
|
|
|
|
// In a loop, read data from the socket and write the data back.
|
|
loop {
|
|
let n = match socket.read(&mut buf).await {
|
|
// socket closed
|
|
Ok(0) => return,
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
println!("failed to read from socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Write the data back
|
|
if let Err(e) = socket.write_all(&buf[0..n]).await {
|
|
println!("failed to write to socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
From within the context of the runtime, additional tasks are spawned using
|
|
the [`tokio::spawn`] function. Futures spawned using this function will be
|
|
executed on the same thread pool used by the [`Runtime`].
|
|
|
|
A [`Runtime`] instance can also be used directly.
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::net::TcpListener;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
use tokio::runtime::Runtime;
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Create the runtime
|
|
let rt = Runtime::new()?;
|
|
|
|
// Spawn the root task
|
|
rt.block_on(async {
|
|
let listener = TcpListener::bind("127.0.0.1:8080").await?;
|
|
|
|
loop {
|
|
let (mut socket, _) = listener.accept().await?;
|
|
|
|
tokio::spawn(async move {
|
|
let mut buf = [0; 1024];
|
|
|
|
// In a loop, read data from the socket and write the data back.
|
|
loop {
|
|
let n = match socket.read(&mut buf).await {
|
|
// socket closed
|
|
Ok(0) => return,
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
println!("failed to read from socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Write the data back
|
|
if let Err(e) = socket.write_all(&buf[0..n]).await {
|
|
println!("failed to write to socket; err = {:?}", e);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
})
|
|
}
|
|
# }
|
|
```
|
|
|
|
## Runtime Configurations
|
|
|
|
Tokio provides multiple task scheduling strategies, suitable for different
|
|
applications. The [runtime builder] or `#[tokio::main]` attribute may be
|
|
used to select which scheduler to use.
|
|
|
|
#### Multi-Thread Scheduler
|
|
|
|
The multi-thread scheduler executes futures on a _thread pool_, using a
|
|
work-stealing strategy. By default, it will start a worker thread for each
|
|
CPU core available on the system. This tends to be the ideal configuration
|
|
for most applications. The multi-thread scheduler requires the `rt-multi-thread`
|
|
feature flag, and is selected by default:
|
|
```
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::runtime;
|
|
|
|
# fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let threaded_rt = runtime::Runtime::new()?;
|
|
# Ok(()) }
|
|
# }
|
|
```
|
|
|
|
Most applications should use the multi-thread scheduler, except in some
|
|
niche use-cases, such as when running only a single thread is required.
|
|
|
|
#### Current-Thread Scheduler
|
|
|
|
The current-thread scheduler provides a _single-threaded_ future executor.
|
|
All tasks will be created and executed on the current thread. This requires
|
|
the `rt` feature flag.
|
|
```
|
|
use tokio::runtime;
|
|
|
|
# fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let rt = runtime::Builder::new_current_thread()
|
|
.build()?;
|
|
# Ok(()) }
|
|
```
|
|
|
|
#### Resource drivers
|
|
|
|
When configuring a runtime by hand, no resource drivers are enabled by
|
|
default. In this case, attempting to use networking types or time types will
|
|
fail. In order to enable these types, the resource drivers must be enabled.
|
|
This is done with [`Builder::enable_io`] and [`Builder::enable_time`]. As a
|
|
shorthand, [`Builder::enable_all`] enables both resource drivers.
|
|
|
|
## Lifetime of spawned threads
|
|
|
|
The runtime may spawn threads depending on its configuration and usage. The
|
|
multi-thread scheduler spawns threads to schedule tasks and for `spawn_blocking`
|
|
calls.
|
|
|
|
While the `Runtime` is active, threads may shut down after periods of being
|
|
idle. Once `Runtime` is dropped, all runtime threads have usually been
|
|
terminated, but in the presence of unstoppable spawned work are not
|
|
guaranteed to have been terminated. See the
|
|
[struct level documentation](Runtime#shutdown) for more details.
|
|
|
|
[tasks]: crate::task
|
|
[`Runtime`]: Runtime
|
|
[`tokio::spawn`]: crate::spawn
|
|
[`tokio::main`]: ../attr.main.html
|
|
[runtime builder]: crate::runtime::Builder
|
|
[`Runtime::new`]: crate::runtime::Runtime::new
|
|
[`Builder::enable_io`]: crate::runtime::Builder::enable_io
|
|
[`Builder::enable_time`]: crate::runtime::Builder::enable_time
|
|
[`Builder::enable_all`]: crate::runtime::Builder::enable_all
|
|
|
|
# Detailed runtime behavior
|
|
|
|
This section gives more details into how the Tokio runtime will schedule
|
|
tasks for execution.
|
|
|
|
At its most basic level, a runtime has a collection of tasks that need to be
|
|
scheduled. It will repeatedly remove a task from that collection and
|
|
schedule it (by calling [`poll`]). When the collection is empty, the thread
|
|
will go to sleep until a task is added to the collection.
|
|
|
|
However, the above is not sufficient to guarantee a well-behaved runtime.
|
|
For example, the runtime might have a single task that is always ready to be
|
|
scheduled, and schedule that task every time. This is a problem because it
|
|
starves other tasks by not scheduling them. To solve this, Tokio provides
|
|
the following fairness guarantee:
|
|
|
|
> If the total number of tasks does not grow without bound, and no task is
|
|
> [blocking the thread], then it is guaranteed that tasks are scheduled
|
|
> fairly.
|
|
|
|
Or, more formally:
|
|
|
|
> Under the following two assumptions:
|
|
>
|
|
> * There is some number `MAX_TASKS` such that the total number of tasks on
|
|
> the runtime at any specific point in time never exceeds `MAX_TASKS`.
|
|
> * There is some number `MAX_SCHEDULE` such that calling [`poll`] on any
|
|
> task spawned on the runtime returns within `MAX_SCHEDULE` time units.
|
|
>
|
|
> Then, there is some number `MAX_DELAY` such that when a task is woken, it
|
|
> will be scheduled by the runtime within `MAX_DELAY` time units.
|
|
|
|
(Here, `MAX_TASKS` and `MAX_SCHEDULE` can be any number and the user of
|
|
the runtime may choose them. The `MAX_DELAY` number is controlled by the
|
|
runtime, and depends on the value of `MAX_TASKS` and `MAX_SCHEDULE`.)
|
|
|
|
Other than the above fairness guarantee, there is no guarantee about the
|
|
order in which tasks are scheduled. There is also no guarantee that the
|
|
runtime is equally fair to all tasks. For example, if the runtime has two
|
|
tasks A and B that are both ready, then the runtime may schedule A five
|
|
times before it schedules B. This is the case even if A yields using
|
|
[`yield_now`]. All that is guaranteed is that it will schedule B eventually.
|
|
|
|
Normally, tasks are scheduled only if they have been woken by calling
|
|
[`wake`] on their waker. However, this is not guaranteed, and Tokio may
|
|
schedule tasks that have not been woken under some circumstances. This is
|
|
called a spurious wakeup.
|
|
|
|
## IO and timers
|
|
|
|
Beyond just scheduling tasks, the runtime must also manage IO resources and
|
|
timers. It does this by periodically checking whether there are any IO
|
|
resources or timers that are ready, and waking the relevant task so that
|
|
it will be scheduled.
|
|
|
|
These checks are performed periodically between scheduling tasks. Under the
|
|
same assumptions as the previous fairness guarantee, Tokio guarantees that
|
|
it will wake tasks with an IO or timer event within some maximum number of
|
|
time units.
|
|
|
|
## Current thread runtime (behavior at the time of writing)
|
|
|
|
This section describes how the [current thread runtime] behaves today. This
|
|
behavior may change in future versions of Tokio.
|
|
|
|
The current thread runtime maintains two FIFO queues of tasks that are ready
|
|
to be scheduled: the global queue and the local queue. The runtime will prefer
|
|
to choose the next task to schedule from the local queue, and will only pick a
|
|
task from the global queue if the local queue is empty, or if it has picked
|
|
a task from the local queue 31 times in a row. The number 31 can be
|
|
changed using the [`global_queue_interval`] setting.
|
|
|
|
The runtime will check for new IO or timer events whenever there are no
|
|
tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
|
|
number 61 may be changed using the [`event_interval`] setting.
|
|
|
|
When a task is woken from within a task running on the runtime, then the
|
|
woken task is added directly to the local queue. Otherwise, the task is
|
|
added to the global queue. The current thread runtime does not use [the lifo
|
|
slot optimization].
|
|
|
|
## Multi threaded runtime (behavior at the time of writing)
|
|
|
|
This section describes how the [multi thread runtime] behaves today. This
|
|
behavior may change in future versions of Tokio.
|
|
|
|
A multi thread runtime has a fixed number of worker threads, which are all
|
|
created on startup. The multi thread runtime maintains one global queue, and
|
|
a local queue for each worker thread. The local queue of a worker thread can
|
|
fit at most 256 tasks. If more than 256 tasks are added to the local queue,
|
|
then half of them are moved to the global queue to make space.
|
|
|
|
The runtime will prefer to choose the next task to schedule from the local
|
|
queue, and will only pick a task from the global queue if the local queue is
|
|
empty, or if it has picked a task from the local queue
|
|
[`global_queue_interval`] times in a row. If the value of
|
|
[`global_queue_interval`] is not explicitly set using the runtime builder,
|
|
then the runtime will dynamically compute it using a heuristic that targets
|
|
10ms intervals between each check of the global queue (based on the
|
|
[`worker_mean_poll_time`] metric).
|
|
|
|
If both the local queue and global queue is empty, then the worker thread
|
|
will attempt to steal tasks from the local queue of another worker thread.
|
|
Stealing is done by moving half of the tasks in one local queue to another
|
|
local queue.
|
|
|
|
The runtime will check for new IO or timer events whenever there are no
|
|
tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
|
|
number 61 may be changed using the [`event_interval`] setting.
|
|
|
|
The multi thread runtime uses [the lifo slot optimization]: Whenever a task
|
|
wakes up another task, the other task is added to the worker thread's lifo
|
|
slot instead of being added to a queue. If there was already a task in the
|
|
lifo slot when this happened, then the lifo slot is replaced, and the task
|
|
that used to be in the lifo slot is placed in the thread's local queue.
|
|
When the runtime finishes scheduling a task, it will schedule the task in
|
|
the lifo slot immediately, if any. When the lifo slot is used, the [coop
|
|
budget] is not reset. Furthermore, if a worker thread uses the lifo slot
|
|
three times in a row, it is temporarily disabled until the worker thread has
|
|
scheduled a task that didn't come from the lifo slot. The lifo slot can be
|
|
disabled using the [`disable_lifo_slot`] setting. The lifo slot is separate
|
|
from the local queue, so other worker threads cannot steal the task in the
|
|
lifo slot.
|
|
|
|
When a task is woken from a thread that is not a worker thread, then the
|
|
task is placed in the global queue.
|
|
|
|
[`poll`]: std::future::Future::poll
|
|
[`wake`]: std::task::Waker::wake
|
|
[`yield_now`]: crate::task::yield_now
|
|
[blocking the thread]: https://ryhl.io/blog/async-what-is-blocking/
|
|
[current thread runtime]: crate::runtime::Builder::new_current_thread
|
|
[multi thread runtime]: crate::runtime::Builder::new_multi_thread
|
|
[`global_queue_interval`]: crate::runtime::Builder::global_queue_interval
|
|
[`event_interval`]: crate::runtime::Builder::event_interval
|
|
[`disable_lifo_slot`]: crate::runtime::Builder::disable_lifo_slot
|
|
[the lifo slot optimization]: crate::runtime::Builder::disable_lifo_slot
|
|
[coop budget]: crate::task::coop#cooperative-scheduling
|
|
[`worker_mean_poll_time`]: crate::runtime::RuntimeMetrics::worker_mean_poll_time
|
|
|
|
```rust
|
|
pub mod runtime { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `dump`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(tokio_unstable, feature = \"taskdump\", feature = \"rt\", target_os =\n\"linux\",\nany(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\")))]")`
|
|
|
|
Snapshots of runtime state.
|
|
|
|
See [`Handle::dump`][crate::runtime::Handle::dump].
|
|
|
|
```rust
|
|
pub mod dump { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `Dump`
|
|
|
|
A snapshot of a runtime's state.
|
|
|
|
See [`Handle::dump`][crate::runtime::Handle::dump].
|
|
|
|
```rust
|
|
pub struct Dump {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn tasks(self: &Self) -> &Tasks { /* ... */ }
|
|
```
|
|
Tasks in this snapshot.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Tasks`
|
|
|
|
Snapshots of tasks.
|
|
|
|
See [`Handle::dump`][crate::runtime::Handle::dump].
|
|
|
|
```rust
|
|
pub struct Tasks {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn iter(self: &Self) -> impl Iterator<Item = &Task> { /* ... */ }
|
|
```
|
|
Iterate over tasks.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Task`
|
|
|
|
A snapshot of a task.
|
|
|
|
See [`Handle::dump`][crate::runtime::Handle::dump].
|
|
|
|
```rust
|
|
pub struct Task {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn id(self: &Self) -> Id { /* ... */ }
|
|
```
|
|
Returns a [task ID] that uniquely identifies this task relative to other
|
|
|
|
- ```rust
|
|
pub fn trace(self: &Self) -> &Trace { /* ... */ }
|
|
```
|
|
A trace of this task's state.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `BacktraceSymbol`
|
|
|
|
A backtrace symbol.
|
|
|
|
This struct provides accessors for backtrace symbols, similar to [`backtrace::BacktraceSymbol`].
|
|
|
|
```rust
|
|
pub struct BacktraceSymbol {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn name_raw(self: &Self) -> Option<&[u8]> { /* ... */ }
|
|
```
|
|
Return the raw name of the symbol.
|
|
|
|
- ```rust
|
|
pub fn name_demangled(self: &Self) -> Option<&str> { /* ... */ }
|
|
```
|
|
Return the demangled name of the symbol.
|
|
|
|
- ```rust
|
|
pub fn addr(self: &Self) -> Option<*mut std::ffi::c_void> { /* ... */ }
|
|
```
|
|
Returns the starting address of this symbol.
|
|
|
|
- ```rust
|
|
pub fn filename(self: &Self) -> Option<&Path> { /* ... */ }
|
|
```
|
|
Returns the file name where this function was defined. If debuginfo
|
|
|
|
- ```rust
|
|
pub fn lineno(self: &Self) -> Option<u32> { /* ... */ }
|
|
```
|
|
Returns the line number for where this symbol is currently executing.
|
|
|
|
- ```rust
|
|
pub fn colno(self: &Self) -> Option<u32> { /* ... */ }
|
|
```
|
|
Returns the column number for where this symbol is currently executing.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> BacktraceSymbol { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `BacktraceFrame`
|
|
|
|
A backtrace frame.
|
|
|
|
This struct represents one stack frame in a captured backtrace, similar to [`backtrace::BacktraceFrame`].
|
|
|
|
```rust
|
|
pub struct BacktraceFrame {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn ip(self: &Self) -> *mut std::ffi::c_void { /* ... */ }
|
|
```
|
|
Return the instruction pointer of this frame.
|
|
|
|
- ```rust
|
|
pub fn symbol_address(self: &Self) -> *mut std::ffi::c_void { /* ... */ }
|
|
```
|
|
Returns the starting symbol address of the frame of this function.
|
|
|
|
- ```rust
|
|
pub fn symbols(self: &Self) -> impl Iterator<Item = &BacktraceSymbol> { /* ... */ }
|
|
```
|
|
Return an iterator over the symbols of this backtrace frame.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> BacktraceFrame { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Backtrace`
|
|
|
|
A captured backtrace.
|
|
|
|
This struct provides access to each backtrace frame, similar to [`backtrace::Backtrace`].
|
|
|
|
```rust
|
|
pub struct Backtrace {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn frames(self: &Self) -> impl Iterator<Item = &BacktraceFrame> { /* ... */ }
|
|
```
|
|
Return the frames in this backtrace, innermost (in a task dump,
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> Backtrace { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Trace`
|
|
|
|
An execution trace of a task's last poll.
|
|
|
|
<div class="warning">
|
|
|
|
Resolving a backtrace, either via the [`Display`][std::fmt::Display] impl or via
|
|
[`resolve_backtraces`][Trace::resolve_backtraces], parses debuginfo, which is
|
|
possibly a CPU-expensive operation that can take a platform-specific but
|
|
long time to run - often over 100 milliseconds, especially if the current
|
|
process's binary is big. In some cases, the platform might internally cache some of the
|
|
debuginfo, so successive calls to `resolve_backtraces` might be faster than
|
|
the first call, but all guarantees are platform-dependent.
|
|
|
|
To avoid blocking the runtime, it is recommended
|
|
that you resolve backtraces inside of a [`spawn_blocking()`][crate::task::spawn_blocking]
|
|
and to have some concurrency-limiting mechanism to avoid unexpected performance impact.
|
|
</div>
|
|
|
|
See [`Handle::dump`][crate::runtime::Handle::dump].
|
|
|
|
```rust
|
|
pub struct Trace {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn resolve_backtraces(self: &Self) -> Vec<Backtrace> { /* ... */ }
|
|
```
|
|
Resolve and return a list of backtraces that are involved in polls in this trace.
|
|
|
|
- ```rust
|
|
pub fn capture<F, R>(f: F) -> (R, Trace)
|
|
where
|
|
F: FnOnce() -> R { /* ... */ }
|
|
```
|
|
Runs the function `f` in tracing mode, and returns its result along with the resulting [`Trace`].
|
|
|
|
- ```rust
|
|
pub fn root<F>(f: F) -> Root<F>
|
|
where
|
|
F: Future { /* ... */ }
|
|
```
|
|
Create a root for stack traces captured using [`Trace::capture`]. Stack frames above
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Re-exports
|
|
|
|
#### Re-export `Root`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::trace::Root;
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `Builder`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use self::builder::Builder;
|
|
```
|
|
|
|
#### Re-export `Id`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
- `Other("#[<cfg_attr>(not(tokio_unstable), allow(unreachable_pub))]")`
|
|
|
|
```rust
|
|
pub use id::Id;
|
|
```
|
|
|
|
#### Re-export `UnhandledPanic`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use self::builder::UnhandledPanic;
|
|
```
|
|
|
|
#### Re-export `RngSeed`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use crate::util::rand::RngSeed;
|
|
```
|
|
|
|
#### Re-export `LocalRuntime`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use local_runtime::LocalRuntime;
|
|
```
|
|
|
|
#### Re-export `LocalOptions`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use local_runtime::LocalOptions;
|
|
```
|
|
|
|
#### Re-export `Dump`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(tokio_unstable, feature = \"taskdump\", feature = \"rt\", target_os =\n\"linux\",\nany(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\")))]")`
|
|
|
|
```rust
|
|
pub use dump::Dump;
|
|
```
|
|
|
|
#### Re-export `TaskMeta`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use task_hooks::TaskMeta;
|
|
```
|
|
|
|
#### Re-export `EnterGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use handle::EnterGuard;
|
|
```
|
|
|
|
#### Re-export `Handle`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use handle::Handle;
|
|
```
|
|
|
|
#### Re-export `TryCurrentError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use handle::TryCurrentError;
|
|
```
|
|
|
|
#### Re-export `Runtime`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use runtime::Runtime;
|
|
```
|
|
|
|
#### Re-export `RuntimeFlavor`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use runtime::RuntimeFlavor;
|
|
```
|
|
|
|
#### Re-export `RuntimeMetrics`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use metrics::RuntimeMetrics;
|
|
```
|
|
|
|
#### Re-export `HistogramScale`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use metrics::HistogramScale;
|
|
```
|
|
|
|
#### Re-export `HistogramConfiguration`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use metrics::HistogramConfiguration;
|
|
```
|
|
|
|
#### Re-export `LogHistogram`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use metrics::LogHistogram;
|
|
```
|
|
|
|
#### Re-export `LogHistogramBuilder`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use metrics::LogHistogramBuilder;
|
|
```
|
|
|
|
#### Re-export `InvalidHistogramConfiguration`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")`
|
|
- `Other("#[doc(cfg(tokio_unstable))]")`
|
|
|
|
```rust
|
|
pub use metrics::InvalidHistogramConfiguration;
|
|
```
|
|
|
|
## Module `signal`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"signal\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"signal\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"signal\"))]")`
|
|
- `Other("#[<cfg>(not(loom))]")`
|
|
- `Other("#[<cfg>(not(target_os = \"wasi\"))]")`
|
|
|
|
Asynchronous signal handling for Tokio.
|
|
|
|
Note that signal handling is in general a very tricky topic and should be
|
|
used with great care. This crate attempts to implement 'best practice' for
|
|
signal handling, but it should be evaluated for your own applications' needs
|
|
to see if it's suitable.
|
|
|
|
There are some fundamental limitations of this crate documented on the OS
|
|
specific structures, as well.
|
|
|
|
# Examples
|
|
|
|
Print on "ctrl-c" notification.
|
|
|
|
```rust,no_run
|
|
use tokio::signal;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
signal::ctrl_c().await?;
|
|
println!("ctrl-c received!");
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
Wait for `SIGHUP` on Unix
|
|
|
|
```rust,no_run
|
|
# #[cfg(unix)] {
|
|
use tokio::signal::unix::{signal, SignalKind};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// An infinite stream of hangup signals.
|
|
let mut stream = signal(SignalKind::hangup())?;
|
|
|
|
// Print whenever a HUP signal is received
|
|
loop {
|
|
stream.recv().await;
|
|
println!("got signal HUP");
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub mod signal { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `unix`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(unix)]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"signal\"))))]")`
|
|
- `Other("#[doc(cfg(all(unix, feature = \"signal\")))]")`
|
|
|
|
Unix-specific types for signal handling.
|
|
|
|
This module is only defined on Unix platforms and contains the primary
|
|
`Signal` type for receiving notifications of signals.
|
|
|
|
```rust
|
|
pub mod unix { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `SignalKind`
|
|
|
|
Represents the specific kind of signal to listen for.
|
|
|
|
```rust
|
|
pub struct SignalKind(/* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub const fn from_raw(signum: std::os::raw::c_int) -> Self { /* ... */ }
|
|
```
|
|
Allows for listening to any valid OS signal.
|
|
|
|
- ```rust
|
|
pub const fn as_raw_value(self: &Self) -> std::os::raw::c_int { /* ... */ }
|
|
```
|
|
Get the signal's numeric value.
|
|
|
|
- ```rust
|
|
pub const fn alarm() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGALRM` signal.
|
|
|
|
- ```rust
|
|
pub const fn child() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGCHLD` signal.
|
|
|
|
- ```rust
|
|
pub const fn hangup() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGHUP` signal.
|
|
|
|
- ```rust
|
|
pub const fn interrupt() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGINT` signal.
|
|
|
|
- ```rust
|
|
pub const fn io() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGIO` signal.
|
|
|
|
- ```rust
|
|
pub const fn pipe() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGPIPE` signal.
|
|
|
|
- ```rust
|
|
pub const fn quit() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGQUIT` signal.
|
|
|
|
- ```rust
|
|
pub const fn terminate() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGTERM` signal.
|
|
|
|
- ```rust
|
|
pub const fn user_defined1() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGUSR1` signal.
|
|
|
|
- ```rust
|
|
pub const fn user_defined2() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGUSR2` signal.
|
|
|
|
- ```rust
|
|
pub const fn window_change() -> Self { /* ... */ }
|
|
```
|
|
Represents the `SIGWINCH` signal.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> SignalKind { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- ```rust
|
|
fn from(signum: std::os::raw::c_int) -> Self { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn from(kind: SignalKind) -> Self { /* ... */ }
|
|
```
|
|
|
|
- **Hash**
|
|
- ```rust
|
|
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &SignalKind) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Signal`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("streams do nothing unless polled") }`
|
|
|
|
An listener for receiving a particular type of OS signal.
|
|
|
|
The listener can be turned into a `Stream` using [`SignalStream`].
|
|
|
|
[`SignalStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.SignalStream.html
|
|
|
|
In general signal handling on Unix is a pretty tricky topic, and this
|
|
structure is no exception! There are some important limitations to keep in
|
|
mind when using `Signal` streams:
|
|
|
|
* Signals handling in Unix already necessitates coalescing signals
|
|
together sometimes. This `Signal` stream is also no exception here in
|
|
that it will also coalesce signals. That is, even if the signal handler
|
|
for this process runs multiple times, the `Signal` stream may only return
|
|
one signal notification. Specifically, before `poll` is called, all
|
|
signal notifications are coalesced into one item returned from `poll`.
|
|
Once `poll` has been called, however, a further signal is guaranteed to
|
|
be yielded as an item.
|
|
|
|
Put another way, any element pulled off the returned listener corresponds to
|
|
*at least one* signal, but possibly more.
|
|
|
|
* Signal handling in general is relatively inefficient. Although some
|
|
improvements are possible in this crate, it's recommended to not plan on
|
|
having millions of signal channels open.
|
|
|
|
If you've got any questions about this feel free to open an issue on the
|
|
repo! New approaches to alleviate some of these limitations are always
|
|
appreciated!
|
|
|
|
# Caveats
|
|
|
|
The first time that a `Signal` instance is registered for a particular
|
|
signal kind, an OS signal-handler is installed which replaces the default
|
|
platform behavior when that signal is received, **for the duration of the
|
|
entire process**.
|
|
|
|
For example, Unix systems will terminate a process by default when it
|
|
receives `SIGINT`. But, when a `Signal` instance is created to listen for
|
|
this signal, the next `SIGINT` that arrives will be translated to a stream
|
|
event, and the process will continue to execute. **Even if this `Signal`
|
|
instance is dropped, subsequent `SIGINT` deliveries will end up captured by
|
|
Tokio, and the default platform behavior will NOT be reset**.
|
|
|
|
Thus, applications should take care to ensure the expected signal behavior
|
|
occurs as expected after listening for specific signals.
|
|
|
|
# Examples
|
|
|
|
Wait for `SIGHUP`
|
|
|
|
```rust,no_run
|
|
use tokio::signal::unix::{signal, SignalKind};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// An infinite stream of hangup signals.
|
|
let mut sig = signal(SignalKind::hangup())?;
|
|
|
|
// Print whenever a HUP signal is received
|
|
loop {
|
|
sig.recv().await;
|
|
println!("got signal HUP");
|
|
}
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub struct Signal {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `signal`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[attr = TrackCaller]")`
|
|
|
|
Creates a new listener which will receive notifications when the current
|
|
process receives the specified signal `kind`.
|
|
|
|
This function will create a new stream which binds to the default reactor.
|
|
The `Signal` stream is an infinite stream which will receive
|
|
notifications whenever a signal is received. More documentation can be
|
|
found on `Signal` itself, but to reiterate:
|
|
|
|
* Signals may be coalesced beyond what the kernel already does.
|
|
* Once a signal handler is registered with the process the underlying
|
|
libc signal handler is never unregistered.
|
|
|
|
A `Signal` stream can be created for a particular signal number
|
|
multiple times. When a signal is received then all the associated
|
|
channels will receive the signal notification.
|
|
|
|
# Errors
|
|
|
|
* If the lower-level C functions fail for some reason.
|
|
* If the previous initialization of this specific signal failed.
|
|
* If the signal is one of
|
|
[`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics)
|
|
|
|
# Panics
|
|
|
|
This function panics if there is no current reactor set, or if the `rt`
|
|
feature flag is not enabled.
|
|
|
|
```rust
|
|
pub fn signal(kind: SignalKind) -> io::Result<Signal> { /* ... */ }
|
|
```
|
|
|
|
## Module `windows`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(windows, docsrs))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(windows, feature = \"signal\"))))]")`
|
|
- `Other("#[doc(cfg(all(windows, feature = \"signal\")))]")`
|
|
|
|
Windows-specific types for signal handling.
|
|
|
|
This module is only defined on Windows and allows receiving "ctrl-c",
|
|
"ctrl-break", "ctrl-logoff", "ctrl-shutdown", and "ctrl-close"
|
|
notifications. These events are listened for via the `SetConsoleCtrlHandler`
|
|
function which receives the corresponding `windows_sys` event type.
|
|
|
|
```rust
|
|
pub mod windows { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `CtrlC`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("listeners do nothing unless polled") }`
|
|
|
|
Represents a listener which receives "ctrl-c" notifications sent to the process
|
|
via `SetConsoleCtrlHandler`.
|
|
|
|
This event can be turned into a `Stream` using [`CtrlCStream`].
|
|
|
|
[`CtrlCStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.CtrlCStream.html
|
|
|
|
A notification to this process notifies *all* receivers for
|
|
this event. Moreover, the notifications **are coalesced** if they aren't processed
|
|
quickly enough. This means that if two notifications are received back-to-back,
|
|
then the listener may only receive one item about the two notifications.
|
|
|
|
```rust
|
|
pub struct CtrlC {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `CtrlBreak`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("listeners do nothing unless polled") }`
|
|
|
|
Represents a listener which receives "ctrl-break" notifications sent to the process
|
|
via `SetConsoleCtrlHandler`.
|
|
|
|
This listener can be turned into a `Stream` using [`CtrlBreakStream`].
|
|
|
|
[`CtrlBreakStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.CtrlBreakStream.html
|
|
|
|
A notification to this process notifies *all* receivers for
|
|
this event. Moreover, the notifications **are coalesced** if they aren't processed
|
|
quickly enough. This means that if two notifications are received back-to-back,
|
|
then the listener may only receive one item about the two notifications.
|
|
|
|
```rust
|
|
pub struct CtrlBreak {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `CtrlClose`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("listeners do nothing unless polled") }`
|
|
|
|
Represents a listener which receives "ctrl-close" notifications sent to the process
|
|
via `SetConsoleCtrlHandler`.
|
|
|
|
A notification to this process notifies *all* listeners listening for
|
|
this event. Moreover, the notifications **are coalesced** if they aren't processed
|
|
quickly enough. This means that if two notifications are received back-to-back,
|
|
then the listener may only receive one item about the two notifications.
|
|
|
|
```rust
|
|
pub struct CtrlClose {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `CtrlShutdown`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("listeners do nothing unless polled") }`
|
|
|
|
Represents a listener which receives "ctrl-shutdown" notifications sent to the process
|
|
via `SetConsoleCtrlHandler`.
|
|
|
|
A notification to this process notifies *all* listeners listening for
|
|
this event. Moreover, the notifications **are coalesced** if they aren't processed
|
|
quickly enough. This means that if two notifications are received back-to-back,
|
|
then the listener may only receive one item about the two notifications.
|
|
|
|
```rust
|
|
pub struct CtrlShutdown {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `CtrlLogoff`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("listeners do nothing unless polled") }`
|
|
|
|
Represents a listener which receives "ctrl-logoff" notifications sent to the process
|
|
via `SetConsoleCtrlHandler`.
|
|
|
|
A notification to this process notifies *all* listeners listening for
|
|
this event. Moreover, the notifications **are coalesced** if they aren't processed
|
|
quickly enough. This means that if two notifications are received back-to-back,
|
|
then the listener may only receive one item about the two notifications.
|
|
|
|
```rust
|
|
pub struct CtrlLogoff {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }
|
|
```
|
|
Receives the next signal notification event.
|
|
|
|
- ```rust
|
|
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }
|
|
```
|
|
Polls to receive the next signal notification event, outside of an
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `ctrl_c`
|
|
|
|
Creates a new listener which receives "ctrl-c" notifications sent to the
|
|
process.
|
|
|
|
# Examples
|
|
|
|
```rust,no_run
|
|
use tokio::signal::windows::ctrl_c;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// A listener of CTRL-C events.
|
|
let mut signal = ctrl_c()?;
|
|
|
|
// Print whenever a CTRL-C event is received.
|
|
for countdown in (0..3).rev() {
|
|
signal.recv().await;
|
|
println!("got CTRL-C. {} more to exit", countdown);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn ctrl_c() -> io::Result<CtrlC> { /* ... */ }
|
|
```
|
|
|
|
#### Function `ctrl_break`
|
|
|
|
Creates a new listener which receives "ctrl-break" notifications sent to the
|
|
process.
|
|
|
|
# Examples
|
|
|
|
```rust,no_run
|
|
use tokio::signal::windows::ctrl_break;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// A listener of CTRL-BREAK events.
|
|
let mut signal = ctrl_break()?;
|
|
|
|
// Print whenever a CTRL-BREAK event is received.
|
|
loop {
|
|
signal.recv().await;
|
|
println!("got signal CTRL-BREAK");
|
|
}
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn ctrl_break() -> io::Result<CtrlBreak> { /* ... */ }
|
|
```
|
|
|
|
#### Function `ctrl_close`
|
|
|
|
Creates a new listener which receives "ctrl-close" notifications sent to the
|
|
process.
|
|
|
|
# Examples
|
|
|
|
```rust,no_run
|
|
use tokio::signal::windows::ctrl_close;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// A listener of CTRL-CLOSE events.
|
|
let mut signal = ctrl_close()?;
|
|
|
|
// Print whenever a CTRL-CLOSE event is received.
|
|
for countdown in (0..3).rev() {
|
|
signal.recv().await;
|
|
println!("got CTRL-CLOSE. {} more to exit", countdown);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn ctrl_close() -> io::Result<CtrlClose> { /* ... */ }
|
|
```
|
|
|
|
#### Function `ctrl_shutdown`
|
|
|
|
Creates a new listener which receives "ctrl-shutdown" notifications sent to the
|
|
process.
|
|
|
|
# Examples
|
|
|
|
```rust,no_run
|
|
use tokio::signal::windows::ctrl_shutdown;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// A listener of CTRL-SHUTDOWN events.
|
|
let mut signal = ctrl_shutdown()?;
|
|
|
|
signal.recv().await;
|
|
println!("got CTRL-SHUTDOWN. Cleaning up before exiting");
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn ctrl_shutdown() -> io::Result<CtrlShutdown> { /* ... */ }
|
|
```
|
|
|
|
#### Function `ctrl_logoff`
|
|
|
|
Creates a new listener which receives "ctrl-logoff" notifications sent to the
|
|
process.
|
|
|
|
# Examples
|
|
|
|
```rust,no_run
|
|
use tokio::signal::windows::ctrl_logoff;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// A listener of CTRL-LOGOFF events.
|
|
let mut signal = ctrl_logoff()?;
|
|
|
|
signal.recv().await;
|
|
println!("got CTRL-LOGOFF. Cleaning up before exiting");
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn ctrl_logoff() -> io::Result<CtrlLogoff> { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `ctrl_c`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"signal\")]")`
|
|
|
|
```rust
|
|
pub use ctrl_c::ctrl_c;
|
|
```
|
|
|
|
## Module `sync`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
- `Other("#[<cfg_attr>(loom, allow(dead_code, unreachable_pub, unused_imports))]")`
|
|
|
|
Synchronization primitives for use in asynchronous contexts.
|
|
|
|
Tokio programs tend to be organized as a set of [tasks] where each task
|
|
operates independently and may be executed on separate physical threads. The
|
|
synchronization primitives provided in this module permit these independent
|
|
tasks to communicate together.
|
|
|
|
[tasks]: crate::task
|
|
|
|
# Message passing
|
|
|
|
The most common form of synchronization in a Tokio program is message
|
|
passing. Two tasks operate independently and send messages to each other to
|
|
synchronize. Doing so has the advantage of avoiding shared state.
|
|
|
|
Message passing is implemented using channels. A channel supports sending a
|
|
message from one producer task to one or more consumer tasks. There are a
|
|
few flavors of channels provided by Tokio. Each channel flavor supports
|
|
different message passing patterns. When a channel supports multiple
|
|
producers, many separate tasks may **send** messages. When a channel
|
|
supports multiple consumers, many different separate tasks may **receive**
|
|
messages.
|
|
|
|
Tokio provides many different channel flavors as different message passing
|
|
patterns are best handled with different implementations.
|
|
|
|
## `oneshot` channel
|
|
|
|
The [`oneshot` channel][oneshot] supports sending a **single** value from a
|
|
single producer to a single consumer. This channel is usually used to send
|
|
the result of a computation to a waiter.
|
|
|
|
**Example:** using a [`oneshot` channel][oneshot] to receive the result of a
|
|
computation.
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
async fn some_computation() -> String {
|
|
"represents the result of the computation".to_string()
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
let res = some_computation().await;
|
|
tx.send(res).unwrap();
|
|
});
|
|
|
|
// Do other work while the computation is happening in the background
|
|
|
|
// Wait for the computation result
|
|
let res = rx.await.unwrap();
|
|
# }
|
|
```
|
|
|
|
Note, if the task produces a computation result as its final
|
|
action before terminating, the [`JoinHandle`] can be used to
|
|
receive that value instead of allocating resources for the
|
|
`oneshot` channel. Awaiting on [`JoinHandle`] returns `Result`. If
|
|
the task panics, the `Joinhandle` yields `Err` with the panic
|
|
cause.
|
|
|
|
**Example:**
|
|
|
|
```
|
|
async fn some_computation() -> String {
|
|
"the result of the computation".to_string()
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let join_handle = tokio::spawn(async move {
|
|
some_computation().await
|
|
});
|
|
|
|
// Do other work while the computation is happening in the background
|
|
|
|
// Wait for the computation result
|
|
let res = join_handle.await.unwrap();
|
|
# }
|
|
```
|
|
|
|
[`JoinHandle`]: crate::task::JoinHandle
|
|
|
|
## `mpsc` channel
|
|
|
|
The [`mpsc` channel][mpsc] supports sending **many** values from **many**
|
|
producers to a single consumer. This channel is often used to send work to a
|
|
task or to receive the result of many computations.
|
|
|
|
This is also the channel you should use if you want to send many messages
|
|
from a single producer to a single consumer. There is no dedicated spsc
|
|
channel.
|
|
|
|
**Example:** using an mpsc to incrementally stream the results of a series
|
|
of computations.
|
|
|
|
```
|
|
use tokio::sync::mpsc;
|
|
|
|
async fn some_computation(input: u32) -> String {
|
|
format!("the result of computation {}", input)
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx) = mpsc::channel(100);
|
|
|
|
tokio::spawn(async move {
|
|
for i in 0..10 {
|
|
let res = some_computation(i).await;
|
|
tx.send(res).await.unwrap();
|
|
}
|
|
});
|
|
|
|
while let Some(res) = rx.recv().await {
|
|
println!("got = {}", res);
|
|
}
|
|
# }
|
|
```
|
|
|
|
The argument to `mpsc::channel` is the channel capacity. This is the maximum
|
|
number of values that can be stored in the channel pending receipt at any
|
|
given time. Properly setting this value is key in implementing robust
|
|
programs as the channel capacity plays a critical part in handling back
|
|
pressure.
|
|
|
|
A common concurrency pattern for resource management is to spawn a task
|
|
dedicated to managing that resource and using message passing between other
|
|
tasks to interact with the resource. The resource may be anything that may
|
|
not be concurrently used. Some examples include a socket and program state.
|
|
For example, if multiple tasks need to send data over a single socket, spawn
|
|
a task to manage the socket and use a channel to synchronize.
|
|
|
|
**Example:** sending data from many tasks over a single socket using message
|
|
passing.
|
|
|
|
```no_run
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::io::{self, AsyncWriteExt};
|
|
use tokio::net::TcpStream;
|
|
use tokio::sync::mpsc;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> io::Result<()> {
|
|
let mut socket = TcpStream::connect("www.example.com:1234").await?;
|
|
let (tx, mut rx) = mpsc::channel(100);
|
|
|
|
for _ in 0..10 {
|
|
// Each task needs its own `tx` handle. This is done by cloning the
|
|
// original handle.
|
|
let tx = tx.clone();
|
|
|
|
tokio::spawn(async move {
|
|
tx.send(&b"data to write"[..]).await.unwrap();
|
|
});
|
|
}
|
|
|
|
// The `rx` half of the channel returns `None` once **all** `tx` clones
|
|
// drop. To ensure `None` is returned, drop the handle owned by the
|
|
// current task. If this `tx` handle is not dropped, there will always
|
|
// be a single outstanding `tx` handle.
|
|
drop(tx);
|
|
|
|
while let Some(res) = rx.recv().await {
|
|
socket.write_all(res).await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
# }
|
|
```
|
|
|
|
The [`mpsc`] and [`oneshot`] channels can be combined to provide a request /
|
|
response type synchronization pattern with a shared resource. A task is
|
|
spawned to synchronize a resource and waits on commands received on a
|
|
[`mpsc`] channel. Each command includes a [`oneshot`] `Sender` on which the
|
|
result of the command is sent.
|
|
|
|
**Example:** use a task to synchronize a `u64` counter. Each task sends an
|
|
"fetch and increment" command. The counter value **before** the increment is
|
|
sent over the provided `oneshot` channel.
|
|
|
|
```
|
|
use tokio::sync::{oneshot, mpsc};
|
|
use Command::Increment;
|
|
|
|
enum Command {
|
|
Increment,
|
|
// Other commands can be added here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (cmd_tx, mut cmd_rx) = mpsc::channel::<(Command, oneshot::Sender<u64>)>(100);
|
|
|
|
// Spawn a task to manage the counter
|
|
tokio::spawn(async move {
|
|
let mut counter: u64 = 0;
|
|
|
|
while let Some((cmd, response)) = cmd_rx.recv().await {
|
|
match cmd {
|
|
Increment => {
|
|
let prev = counter;
|
|
counter += 1;
|
|
response.send(prev).unwrap();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
let mut join_handles = vec![];
|
|
|
|
// Spawn tasks that will send the increment command.
|
|
for _ in 0..10 {
|
|
let cmd_tx = cmd_tx.clone();
|
|
|
|
join_handles.push(tokio::spawn(async move {
|
|
let (resp_tx, resp_rx) = oneshot::channel();
|
|
|
|
cmd_tx.send((Increment, resp_tx)).await.ok().unwrap();
|
|
let res = resp_rx.await.unwrap();
|
|
|
|
println!("previous value = {}", res);
|
|
}));
|
|
}
|
|
|
|
// Wait for all tasks to complete
|
|
for join_handle in join_handles.drain(..) {
|
|
join_handle.await.unwrap();
|
|
}
|
|
# }
|
|
```
|
|
|
|
## `broadcast` channel
|
|
|
|
The [`broadcast` channel] supports sending **many** values from
|
|
**many** producers to **many** consumers. Each consumer will receive
|
|
**each** value. This channel can be used to implement "fan out" style
|
|
patterns common with pub / sub or "chat" systems.
|
|
|
|
This channel tends to be used less often than `oneshot` and `mpsc` but still
|
|
has its use cases.
|
|
|
|
This is also the channel you should use if you want to broadcast values from
|
|
a single producer to many consumers. There is no dedicated spmc broadcast
|
|
channel.
|
|
|
|
Basic usage
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx1) = broadcast::channel(16);
|
|
let mut rx2 = tx.subscribe();
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx1.recv().await.unwrap(), 10);
|
|
assert_eq!(rx1.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx2.recv().await.unwrap(), 10);
|
|
assert_eq!(rx2.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
# }
|
|
```
|
|
|
|
[`broadcast` channel]: crate::sync::broadcast
|
|
|
|
## `watch` channel
|
|
|
|
The [`watch` channel] supports sending **many** values from **many**
|
|
producers to **many** consumers. However, only the **most recent** value is
|
|
stored in the channel. Consumers are notified when a new value is sent, but
|
|
there is no guarantee that consumers will see **all** values.
|
|
|
|
The [`watch` channel] is similar to a [`broadcast` channel] with capacity 1.
|
|
|
|
Use cases for the [`watch` channel] include broadcasting configuration
|
|
changes or signalling program state changes, such as transitioning to
|
|
shutdown.
|
|
|
|
**Example:** use a [`watch` channel] to notify tasks of configuration
|
|
changes. In this example, a configuration file is checked periodically. When
|
|
the file changes, the configuration changes are signalled to consumers.
|
|
|
|
```
|
|
use tokio::sync::watch;
|
|
use tokio::time::{self, Duration, Instant};
|
|
|
|
use std::io;
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
struct Config {
|
|
timeout: Duration,
|
|
}
|
|
|
|
impl Config {
|
|
async fn load_from_file() -> io::Result<Config> {
|
|
// file loading and deserialization logic here
|
|
# Ok(Config { timeout: Duration::from_secs(1) })
|
|
}
|
|
}
|
|
|
|
async fn my_async_operation() {
|
|
// Do something here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
// Load initial configuration value
|
|
let mut config = Config::load_from_file().await.unwrap();
|
|
|
|
// Create the watch channel, initialized with the loaded configuration
|
|
let (tx, rx) = watch::channel(config.clone());
|
|
|
|
// Spawn a task to monitor the file.
|
|
tokio::spawn(async move {
|
|
loop {
|
|
// Wait 10 seconds between checks
|
|
time::sleep(Duration::from_secs(10)).await;
|
|
|
|
// Load the configuration file
|
|
let new_config = Config::load_from_file().await.unwrap();
|
|
|
|
// If the configuration changed, send the new config value
|
|
// on the watch channel.
|
|
if new_config != config {
|
|
tx.send(new_config.clone()).unwrap();
|
|
config = new_config;
|
|
}
|
|
}
|
|
});
|
|
|
|
let mut handles = vec![];
|
|
|
|
// Spawn tasks that runs the async operation for at most `timeout`. If
|
|
// the timeout elapses, restart the operation.
|
|
//
|
|
// The task simultaneously watches the `Config` for changes. When the
|
|
// timeout duration changes, the timeout is updated without restarting
|
|
// the in-flight operation.
|
|
for _ in 0..5 {
|
|
// Clone a config watch handle for use in this task
|
|
let mut rx = rx.clone();
|
|
|
|
let handle = tokio::spawn(async move {
|
|
// Start the initial operation and pin the future to the stack.
|
|
// Pinning to the stack is required to resume the operation
|
|
// across multiple calls to `select!`
|
|
let op = my_async_operation();
|
|
tokio::pin!(op);
|
|
|
|
// Get the initial config value
|
|
let mut conf = rx.borrow().clone();
|
|
|
|
let mut op_start = Instant::now();
|
|
let sleep = time::sleep_until(op_start + conf.timeout);
|
|
tokio::pin!(sleep);
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = &mut sleep => {
|
|
// The operation elapsed. Restart it
|
|
op.set(my_async_operation());
|
|
|
|
// Track the new start time
|
|
op_start = Instant::now();
|
|
|
|
// Restart the timeout
|
|
sleep.set(time::sleep_until(op_start + conf.timeout));
|
|
}
|
|
_ = rx.changed() => {
|
|
conf = rx.borrow_and_update().clone();
|
|
|
|
// The configuration has been updated. Update the
|
|
// `sleep` using the new `timeout` value.
|
|
sleep.as_mut().reset(op_start + conf.timeout);
|
|
}
|
|
_ = &mut op => {
|
|
// The operation completed!
|
|
return
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
handles.push(handle);
|
|
}
|
|
|
|
for handle in handles.drain(..) {
|
|
handle.await.unwrap();
|
|
}
|
|
# }
|
|
```
|
|
|
|
[`watch` channel]: mod@crate::sync::watch
|
|
[`broadcast` channel]: mod@crate::sync::broadcast
|
|
|
|
# State synchronization
|
|
|
|
The remaining synchronization primitives focus on synchronizing state.
|
|
These are asynchronous equivalents to versions provided by `std`. They
|
|
operate in a similar way as their `std` counterparts but will wait
|
|
asynchronously instead of blocking the thread.
|
|
|
|
* [`Barrier`] Ensures multiple tasks will wait for each other to reach a
|
|
point in the program, before continuing execution all together.
|
|
|
|
* [`Mutex`] Mutual Exclusion mechanism, which ensures that at most one
|
|
thread at a time is able to access some data.
|
|
|
|
* [`Notify`] Basic task notification. `Notify` supports notifying a
|
|
receiving task without sending data. In this case, the task wakes up and
|
|
resumes processing.
|
|
|
|
* [`RwLock`] Provides a mutual exclusion mechanism which allows multiple
|
|
readers at the same time, while allowing only one writer at a time. In
|
|
some cases, this can be more efficient than a mutex.
|
|
|
|
* [`Semaphore`] Limits the amount of concurrency. A semaphore holds a
|
|
number of permits, which tasks may request in order to enter a critical
|
|
section. Semaphores are useful for implementing limiting or bounding of
|
|
any kind.
|
|
|
|
# Runtime compatibility
|
|
|
|
All synchronization primitives provided in this module are runtime agnostic.
|
|
You can freely move them between different instances of the Tokio runtime
|
|
or even use them from non-Tokio runtimes.
|
|
|
|
When used in a Tokio runtime, the synchronization primitives participate in
|
|
[cooperative scheduling](crate::task::coop#cooperative-scheduling) to avoid
|
|
starvation. This feature does not apply when used from non-Tokio runtimes.
|
|
|
|
As an exception, methods ending in `_timeout` are not runtime agnostic
|
|
because they require access to the Tokio timer. See the documentation of
|
|
each `*_timeout` method for more information on its use.
|
|
|
|
```rust
|
|
pub mod sync { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `futures`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
Named future types.
|
|
|
|
```rust
|
|
pub mod futures { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `Notified`
|
|
|
|
```rust
|
|
pub use super::notify::Notified;
|
|
```
|
|
|
|
#### Re-export `OwnedNotified`
|
|
|
|
```rust
|
|
pub use super::notify::OwnedNotified;
|
|
```
|
|
|
|
## Module `broadcast`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
A multi-producer, multi-consumer broadcast queue. Each sent value is seen by
|
|
all consumers.
|
|
|
|
A [`Sender`] is used to broadcast values to **all** connected [`Receiver`]
|
|
values. [`Sender`] handles are clone-able, allowing concurrent send and
|
|
receive actions. [`Sender`] and [`Receiver`] are both `Send` and `Sync` as
|
|
long as `T` is `Send`.
|
|
|
|
When a value is sent, **all** [`Receiver`] handles are notified and will
|
|
receive the value. The value is stored once inside the channel and cloned on
|
|
demand for each receiver. Once all receivers have received a clone of the
|
|
value, the value is released from the channel.
|
|
|
|
A channel is created by calling [`channel`], specifying the maximum number
|
|
of messages the channel can retain at any given time.
|
|
|
|
New [`Receiver`] handles are created by calling [`Sender::subscribe`]. The
|
|
returned [`Receiver`] will receive values sent **after** the call to
|
|
`subscribe`.
|
|
|
|
This channel is also suitable for the single-producer multi-consumer
|
|
use-case, where a single sender broadcasts values to many receivers.
|
|
|
|
## Lagging
|
|
|
|
As sent messages must be retained until **all** [`Receiver`] handles receive
|
|
a clone, broadcast channels are susceptible to the "slow receiver" problem.
|
|
In this case, all but one receiver are able to receive values at the rate
|
|
they are sent. Because one receiver is stalled, the channel starts to fill
|
|
up.
|
|
|
|
This broadcast channel implementation handles this case by setting a hard
|
|
upper bound on the number of values the channel may retain at any given
|
|
time. This upper bound is passed to the [`channel`] function as an argument.
|
|
|
|
If a value is sent when the channel is at capacity, the oldest value
|
|
currently held by the channel is released. This frees up space for the new
|
|
value. Any receiver that has not yet seen the released value will return
|
|
[`RecvError::Lagged`] the next time [`recv`] is called.
|
|
|
|
Once [`RecvError::Lagged`] is returned, the lagging receiver's position is
|
|
updated to the oldest value contained by the channel. The next call to
|
|
[`recv`] will return this value.
|
|
|
|
This behavior enables a receiver to detect when it has lagged so far behind
|
|
that data has been dropped. The caller may decide how to respond to this:
|
|
either by aborting its task or by tolerating lost messages and resuming
|
|
consumption of the channel.
|
|
|
|
## Closing
|
|
|
|
When **all** [`Sender`] handles have been dropped, no new values may be
|
|
sent. At this point, the channel is "closed". Once a receiver has received
|
|
all values retained by the channel, the next call to [`recv`] will return
|
|
with [`RecvError::Closed`].
|
|
|
|
When a [`Receiver`] handle is dropped, any messages not read by the receiver
|
|
will be marked as read. If this receiver was the only one not to have read
|
|
that message, the message will be dropped at this point.
|
|
|
|
[`Sender`]: crate::sync::broadcast::Sender
|
|
[`Sender::subscribe`]: crate::sync::broadcast::Sender::subscribe
|
|
[`Receiver`]: crate::sync::broadcast::Receiver
|
|
[`channel`]: crate::sync::broadcast::channel
|
|
[`RecvError::Lagged`]: crate::sync::broadcast::error::RecvError::Lagged
|
|
[`RecvError::Closed`]: crate::sync::broadcast::error::RecvError::Closed
|
|
[`recv`]: crate::sync::broadcast::Receiver::recv
|
|
|
|
# Examples
|
|
|
|
Basic usage
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx1) = broadcast::channel(16);
|
|
let mut rx2 = tx.subscribe();
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx1.recv().await.unwrap(), 10);
|
|
assert_eq!(rx1.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx2.recv().await.unwrap(), 10);
|
|
assert_eq!(rx2.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
# }
|
|
```
|
|
|
|
Handling lag
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx) = broadcast::channel(2);
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
tx.send(30).unwrap();
|
|
|
|
// The receiver lagged behind
|
|
assert!(rx.recv().await.is_err());
|
|
|
|
// At this point, we can abort or continue with lost messages
|
|
|
|
assert_eq!(20, rx.recv().await.unwrap());
|
|
assert_eq!(30, rx.recv().await.unwrap());
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub mod broadcast { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `error`
|
|
|
|
Broadcast error types
|
|
|
|
```rust
|
|
pub mod error { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `SendError`
|
|
|
|
Error returned by the [`send`] function on a [`Sender`].
|
|
|
|
A **send** operation can only fail if there are no active receivers,
|
|
implying that the message could never be received. The error contains the
|
|
message being sent as a payload so it can be recovered.
|
|
|
|
[`send`]: crate::sync::broadcast::Sender::send
|
|
[`Sender`]: crate::sync::broadcast::Sender
|
|
|
|
```rust
|
|
pub struct SendError<T>(pub T);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `RecvError`
|
|
|
|
An error returned from the [`recv`] function on a [`Receiver`].
|
|
|
|
[`recv`]: crate::sync::broadcast::Receiver::recv
|
|
[`Receiver`]: crate::sync::broadcast::Receiver
|
|
|
|
```rust
|
|
pub enum RecvError {
|
|
Closed,
|
|
Lagged(u64),
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Closed`
|
|
|
|
There are no more active senders implying no further messages will ever
|
|
be sent.
|
|
|
|
###### `Lagged`
|
|
|
|
The receiver lagged too far behind. Attempting to receive again will
|
|
return the oldest message still retained by the channel.
|
|
|
|
Includes the number of skipped messages.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `u64` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> RecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &RecvError) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `TryRecvError`
|
|
|
|
An error returned from the [`try_recv`] function on a [`Receiver`].
|
|
|
|
[`try_recv`]: crate::sync::broadcast::Receiver::try_recv
|
|
[`Receiver`]: crate::sync::broadcast::Receiver
|
|
|
|
```rust
|
|
pub enum TryRecvError {
|
|
Empty,
|
|
Closed,
|
|
Lagged(u64),
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Empty`
|
|
|
|
The channel is currently empty. There are still active
|
|
[`Sender`] handles, so data may yet become available.
|
|
|
|
[`Sender`]: crate::sync::broadcast::Sender
|
|
|
|
###### `Closed`
|
|
|
|
There are no more active senders implying no further messages will ever
|
|
be sent.
|
|
|
|
###### `Lagged`
|
|
|
|
The receiver lagged too far behind and has been forcibly disconnected.
|
|
Attempting to receive again will return the oldest message still
|
|
retained by the channel.
|
|
|
|
Includes the number of skipped messages.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `u64` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> TryRecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Types
|
|
|
|
#### Struct `Sender`
|
|
|
|
Sending-half of the [`broadcast`] channel.
|
|
|
|
May be used from many threads. Messages can be sent with
|
|
[`send`][Sender::send].
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx1) = broadcast::channel(16);
|
|
let mut rx2 = tx.subscribe();
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx1.recv().await.unwrap(), 10);
|
|
assert_eq!(rx1.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx2.recv().await.unwrap(), 10);
|
|
assert_eq!(rx2.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
# }
|
|
```
|
|
|
|
[`broadcast`]: crate::sync::broadcast
|
|
|
|
```rust
|
|
pub struct Sender<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new(capacity: usize) -> Self { /* ... */ }
|
|
```
|
|
Creates the sending-half of the [`broadcast`] channel.
|
|
|
|
- ```rust
|
|
pub fn send(self: &Self, value: T) -> Result<usize, SendError<T>> { /* ... */ }
|
|
```
|
|
Attempts to send a value to all active [`Receiver`] handles, returning
|
|
|
|
- ```rust
|
|
pub fn subscribe(self: &Self) -> Receiver<T> { /* ... */ }
|
|
```
|
|
Creates a new [`Receiver`] handle that will receive values sent **after**
|
|
|
|
- ```rust
|
|
pub fn downgrade(self: &Self) -> WeakSender<T> { /* ... */ }
|
|
```
|
|
Converts the `Sender` to a [`WeakSender`] that does not count
|
|
|
|
- ```rust
|
|
pub fn len(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of queued values.
|
|
|
|
- ```rust
|
|
pub fn is_empty(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns true if there are no queued values.
|
|
|
|
- ```rust
|
|
pub fn receiver_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of active receivers.
|
|
|
|
- ```rust
|
|
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if senders belong to the same channel.
|
|
|
|
- ```rust
|
|
pub async fn closed(self: &Self) { /* ... */ }
|
|
```
|
|
A future which completes when the number of [Receiver]s subscribed to this `Sender` reaches
|
|
|
|
- ```rust
|
|
pub fn strong_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`Sender`] handles.
|
|
|
|
- ```rust
|
|
pub fn weak_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`WeakSender`] handles.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> Sender<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `WeakSender`
|
|
|
|
A sender that does not prevent the channel from being closed.
|
|
|
|
If all [`Sender`] instances of a channel were dropped and only `WeakSender`
|
|
instances remain, the channel is closed.
|
|
|
|
In order to send messages, the `WeakSender` needs to be upgraded using
|
|
[`WeakSender::upgrade`], which returns `Option<Sender>`. It returns `None`
|
|
if all `Sender`s have been dropped, and otherwise it returns a `Sender`.
|
|
|
|
[`Sender`]: Sender
|
|
[`WeakSender::upgrade`]: WeakSender::upgrade
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::broadcast::channel;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, _rx) = channel::<i32>(15);
|
|
let tx_weak = tx.downgrade();
|
|
|
|
// Upgrading will succeed because `tx` still exists.
|
|
assert!(tx_weak.upgrade().is_some());
|
|
|
|
// If we drop `tx`, then it will fail.
|
|
drop(tx);
|
|
assert!(tx_weak.clone().upgrade().is_none());
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub struct WeakSender<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn upgrade(self: &Self) -> Option<Sender<T>> { /* ... */ }
|
|
```
|
|
Tries to convert a `WeakSender` into a [`Sender`].
|
|
|
|
- ```rust
|
|
pub fn strong_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`Sender`] handles.
|
|
|
|
- ```rust
|
|
pub fn weak_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`WeakSender`] handles.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> WeakSender<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Receiver`
|
|
|
|
Receiving-half of the [`broadcast`] channel.
|
|
|
|
Must not be used concurrently. Messages may be retrieved using
|
|
[`recv`][Receiver::recv].
|
|
|
|
To turn this receiver into a `Stream`, you can use the [`BroadcastStream`]
|
|
wrapper.
|
|
|
|
[`BroadcastStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.BroadcastStream.html
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx1) = broadcast::channel(16);
|
|
let mut rx2 = tx.subscribe();
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx1.recv().await.unwrap(), 10);
|
|
assert_eq!(rx1.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx2.recv().await.unwrap(), 10);
|
|
assert_eq!(rx2.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
# }
|
|
```
|
|
|
|
[`broadcast`]: crate::sync::broadcast
|
|
|
|
```rust
|
|
pub struct Receiver<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn len(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of messages that were sent into the channel and that
|
|
|
|
- ```rust
|
|
pub fn is_empty(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns true if there aren't any messages in the channel that the [`Receiver`]
|
|
|
|
- ```rust
|
|
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if receivers belong to the same channel.
|
|
|
|
- ```rust
|
|
pub fn sender_strong_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`Sender`] handles.
|
|
|
|
- ```rust
|
|
pub fn sender_weak_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of [`WeakSender`] handles.
|
|
|
|
- ```rust
|
|
pub fn is_closed(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Checks if a channel is closed.
|
|
|
|
- ```rust
|
|
pub fn resubscribe(self: &Self) -> Self { /* ... */ }
|
|
```
|
|
Re-subscribes to the channel starting from the current tail element.
|
|
|
|
- ```rust
|
|
pub async fn recv(self: &mut Self) -> Result<T, RecvError> { /* ... */ }
|
|
```
|
|
Receives the next value for this receiver.
|
|
|
|
- ```rust
|
|
pub fn try_recv(self: &mut Self) -> Result<T, TryRecvError> { /* ... */ }
|
|
```
|
|
Attempts to return a pending value on this receiver without awaiting.
|
|
|
|
- ```rust
|
|
pub fn blocking_recv(self: &mut Self) -> Result<T, RecvError> { /* ... */ }
|
|
```
|
|
Blocking receive to call outside of asynchronous contexts.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `channel`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[attr = TrackCaller]")`
|
|
|
|
Create a bounded, multi-producer, multi-consumer channel where each sent
|
|
value is broadcasted to all active receivers.
|
|
|
|
**Note:** The actual capacity may be greater than the provided `capacity`.
|
|
|
|
All data sent on [`Sender`] will become available on every active
|
|
[`Receiver`] in the same order as it was sent.
|
|
|
|
The `Sender` can be cloned to `send` to the same channel from multiple
|
|
points in the process or it can be used concurrently from an `Arc`. New
|
|
`Receiver` handles are created by calling [`Sender::subscribe`].
|
|
|
|
If all [`Receiver`] handles are dropped, the `send` method will return a
|
|
[`SendError`]. Similarly, if all [`Sender`] handles are dropped, the [`recv`]
|
|
method will return a [`RecvError`].
|
|
|
|
[`Sender`]: crate::sync::broadcast::Sender
|
|
[`Sender::subscribe`]: crate::sync::broadcast::Sender::subscribe
|
|
[`Receiver`]: crate::sync::broadcast::Receiver
|
|
[`recv`]: crate::sync::broadcast::Receiver::recv
|
|
[`SendError`]: crate::sync::broadcast::error::SendError
|
|
[`RecvError`]: crate::sync::broadcast::error::RecvError
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::broadcast;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx1) = broadcast::channel(16);
|
|
let mut rx2 = tx.subscribe();
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx1.recv().await.unwrap(), 10);
|
|
assert_eq!(rx1.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
assert_eq!(rx2.recv().await.unwrap(), 10);
|
|
assert_eq!(rx2.recv().await.unwrap(), 20);
|
|
});
|
|
|
|
tx.send(10).unwrap();
|
|
tx.send(20).unwrap();
|
|
# }
|
|
```
|
|
|
|
# Panics
|
|
|
|
This will panic if `capacity` is equal to `0`.
|
|
|
|
This pre-allocates space for `capacity` messages. Allocation failure may result in a panic or
|
|
[an allocation error](std::alloc::handle_alloc_error).
|
|
|
|
```rust
|
|
pub fn channel<T: Clone>(capacity: usize) -> (Sender<T>, Receiver<T>) { /* ... */ }
|
|
```
|
|
|
|
## Module `mpsc`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
- `Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")`
|
|
|
|
A multi-producer, single-consumer queue for sending values between
|
|
asynchronous tasks.
|
|
|
|
This module provides two variants of the channel: bounded and unbounded. The
|
|
bounded variant has a limit on the number of messages that the channel can
|
|
store, and if this limit is reached, trying to send another message will
|
|
wait until a message is received from the channel. An unbounded channel has
|
|
an infinite capacity, so the `send` method will always complete immediately.
|
|
This makes the [`UnboundedSender`] usable from both synchronous and
|
|
asynchronous code.
|
|
|
|
Similar to the `mpsc` channels provided by `std`, the channel constructor
|
|
functions provide separate send and receive handles, [`Sender`] and
|
|
[`Receiver`] for the bounded channel, [`UnboundedSender`] and
|
|
[`UnboundedReceiver`] for the unbounded channel. If there is no message to read,
|
|
the current task will be notified when a new value is sent. [`Sender`] and
|
|
[`UnboundedSender`] allow sending values into the channel. If the bounded
|
|
channel is at capacity, the send is rejected and the task will be notified
|
|
when additional capacity is available. In other words, the channel provides
|
|
backpressure.
|
|
|
|
This channel is also suitable for the single-producer single-consumer
|
|
use-case. (Unless you only need to send one message, in which case you
|
|
should use the [oneshot] channel.)
|
|
|
|
# Disconnection
|
|
|
|
When all [`Sender`] handles have been dropped, it is no longer
|
|
possible to send values into the channel. This is considered the termination
|
|
event of the stream. As such, `Receiver::poll` returns `Ok(Ready(None))`.
|
|
|
|
If the [`Receiver`] handle is dropped, then messages can no longer
|
|
be read out of the channel. In this case, all further attempts to send will
|
|
result in an error. Additionally, all unread messages will be drained from the
|
|
channel and dropped.
|
|
|
|
# Clean Shutdown
|
|
|
|
When the [`Receiver`] is dropped, it is possible for unprocessed messages to
|
|
remain in the channel. Instead, it is usually desirable to perform a "clean"
|
|
shutdown. To do this, the receiver first calls `close`, which will prevent
|
|
any further messages to be sent into the channel. Then, the receiver
|
|
consumes the channel to completion, at which point the receiver can be
|
|
dropped.
|
|
|
|
# Communicating between sync and async code
|
|
|
|
When you want to communicate between synchronous and asynchronous code, there
|
|
are two situations to consider:
|
|
|
|
**Bounded channel**: If you need a bounded channel, you should use a bounded
|
|
Tokio `mpsc` channel for both directions of communication. Instead of calling
|
|
the async [`send`][bounded-send] or [`recv`][bounded-recv] methods, in
|
|
synchronous code you will need to use the [`blocking_send`][blocking-send] or
|
|
[`blocking_recv`][blocking-recv] methods.
|
|
|
|
**Unbounded channel**: You should use the kind of channel that matches where
|
|
the receiver is. So for sending a message _from async to sync_, you should
|
|
use [the standard library unbounded channel][std-unbounded] or
|
|
[crossbeam][crossbeam-unbounded]. Similarly, for sending a message _from sync
|
|
to async_, you should use an unbounded Tokio `mpsc` channel.
|
|
|
|
Please be aware that the above remarks were written with the `mpsc` channel
|
|
in mind, but they can also be generalized to other kinds of channels. In
|
|
general, any channel method that isn't marked async can be called anywhere,
|
|
including outside of the runtime. For example, sending a message on a
|
|
[oneshot] channel from outside the runtime is perfectly fine.
|
|
|
|
# Multiple runtimes
|
|
|
|
The `mpsc` channel is runtime agnostic. You can freely move it between
|
|
different instances of the Tokio runtime or even use it from non-Tokio
|
|
runtimes.
|
|
|
|
When used in a Tokio runtime, it participates in
|
|
[cooperative scheduling](crate::task::coop#cooperative-scheduling) to avoid
|
|
starvation. This feature does not apply when used from non-Tokio runtimes.
|
|
|
|
As an exception, methods ending in `_timeout` are not runtime agnostic
|
|
because they require access to the Tokio timer. See the documentation of
|
|
each `*_timeout` method for more information on its use.
|
|
|
|
# Allocation behavior
|
|
|
|
<div class="warning">The implementation details described in this section may change in future
|
|
Tokio releases.</div>
|
|
|
|
The mpsc channel stores elements in blocks. Blocks are organized in a linked list. Sending
|
|
pushes new elements onto the block at the front of the list, and receiving pops them off the
|
|
one at the back. A block can hold 32 messages on a 64-bit target and 16 messages on a 32-bit
|
|
target. This number is independent of channel and message size. Each block also stores 4
|
|
pointer-sized values for bookkeeping (so on a 64-bit machine, each message has 1 byte of
|
|
overhead).
|
|
|
|
When all values in a block have been received, it becomes empty. It will then be freed, unless
|
|
the channel's first block (where newly-sent elements are being stored) has no next block. In
|
|
that case, the empty block is reused as the next block.
|
|
|
|
[`Sender`]: crate::sync::mpsc::Sender
|
|
[`Receiver`]: crate::sync::mpsc::Receiver
|
|
[bounded-send]: crate::sync::mpsc::Sender::send()
|
|
[bounded-recv]: crate::sync::mpsc::Receiver::recv()
|
|
[blocking-send]: crate::sync::mpsc::Sender::blocking_send()
|
|
[blocking-recv]: crate::sync::mpsc::Receiver::blocking_recv()
|
|
[`UnboundedSender`]: crate::sync::mpsc::UnboundedSender
|
|
[`UnboundedReceiver`]: crate::sync::mpsc::UnboundedReceiver
|
|
[oneshot]: crate::sync::oneshot
|
|
[`Handle::block_on`]: crate::runtime::Handle::block_on()
|
|
[std-unbounded]: std::sync::mpsc::channel
|
|
[crossbeam-unbounded]: https://docs.rs/crossbeam/*/crossbeam/channel/fn.unbounded.html
|
|
[`send_timeout`]: crate::sync::mpsc::Sender::send_timeout
|
|
|
|
```rust
|
|
pub mod mpsc { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `error`
|
|
|
|
Channel error types.
|
|
|
|
```rust
|
|
pub mod error { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `SendError`
|
|
|
|
Error returned by the `Sender`.
|
|
|
|
```rust
|
|
pub struct SendError<T>(pub T);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> SendError<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- ```rust
|
|
fn from(src: SendError<T>) -> TrySendError<T> { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &SendError<T>) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `TrySendError`
|
|
|
|
This enumeration is the list of the possible error outcomes for the
|
|
[`try_send`](super::Sender::try_send) method.
|
|
|
|
```rust
|
|
pub enum TrySendError<T> {
|
|
Full(T),
|
|
Closed(T),
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Full`
|
|
|
|
The data could not be sent on the channel because the channel is
|
|
currently full and sending would require blocking.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
###### `Closed`
|
|
|
|
The receive half of the channel was explicitly closed or has been
|
|
dropped.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn into_inner(self: Self) -> T { /* ... */ }
|
|
```
|
|
Consume the `TrySendError`, returning the unsent value.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> TrySendError<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- ```rust
|
|
fn from(src: SendError<T>) -> TrySendError<T> { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &TrySendError<T>) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `TryRecvError`
|
|
|
|
Error returned by `try_recv`.
|
|
|
|
```rust
|
|
pub enum TryRecvError {
|
|
Empty,
|
|
Disconnected,
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Empty`
|
|
|
|
This **channel** is currently empty, but the **Sender**(s) have not yet
|
|
disconnected, so data may yet become available.
|
|
|
|
###### `Disconnected`
|
|
|
|
The **channel**'s sending half has become disconnected, and there will
|
|
never be any more data received on it.
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> TryRecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `SendTimeoutError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"time\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"time\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"time\"))]")`
|
|
|
|
Error returned by [`Sender::send_timeout`](super::Sender::send_timeout)].
|
|
|
|
```rust
|
|
pub enum SendTimeoutError<T> {
|
|
Timeout(T),
|
|
Closed(T),
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Timeout`
|
|
|
|
The data could not be sent on the channel because the channel is
|
|
full, and the timeout to send has elapsed.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
###### `Closed`
|
|
|
|
The receive half of the channel was explicitly closed or has been
|
|
dropped.
|
|
|
|
Fields:
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn into_inner(self: Self) -> T { /* ... */ }
|
|
```
|
|
Consume the `SendTimeoutError`, returning the unsent value.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> SendTimeoutError<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &SendTimeoutError<T>) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Re-exports
|
|
|
|
#### Re-export `channel`
|
|
|
|
```rust
|
|
pub use self::bounded::channel;
|
|
```
|
|
|
|
#### Re-export `OwnedPermit`
|
|
|
|
```rust
|
|
pub use self::bounded::OwnedPermit;
|
|
```
|
|
|
|
#### Re-export `Permit`
|
|
|
|
```rust
|
|
pub use self::bounded::Permit;
|
|
```
|
|
|
|
#### Re-export `PermitIterator`
|
|
|
|
```rust
|
|
pub use self::bounded::PermitIterator;
|
|
```
|
|
|
|
#### Re-export `Receiver`
|
|
|
|
```rust
|
|
pub use self::bounded::Receiver;
|
|
```
|
|
|
|
#### Re-export `Sender`
|
|
|
|
```rust
|
|
pub use self::bounded::Sender;
|
|
```
|
|
|
|
#### Re-export `WeakSender`
|
|
|
|
```rust
|
|
pub use self::bounded::WeakSender;
|
|
```
|
|
|
|
#### Re-export `unbounded_channel`
|
|
|
|
```rust
|
|
pub use self::unbounded::unbounded_channel;
|
|
```
|
|
|
|
#### Re-export `UnboundedReceiver`
|
|
|
|
```rust
|
|
pub use self::unbounded::UnboundedReceiver;
|
|
```
|
|
|
|
#### Re-export `UnboundedSender`
|
|
|
|
```rust
|
|
pub use self::unbounded::UnboundedSender;
|
|
```
|
|
|
|
#### Re-export `WeakUnboundedSender`
|
|
|
|
```rust
|
|
pub use self::unbounded::WeakUnboundedSender;
|
|
```
|
|
|
|
## Module `oneshot`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
- `Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")`
|
|
|
|
A one-shot channel is used for sending a single message between
|
|
asynchronous tasks. The [`channel`] function is used to create a
|
|
[`Sender`] and [`Receiver`] handle pair that form the channel.
|
|
|
|
The `Sender` handle is used by the producer to send the value.
|
|
The `Receiver` handle is used by the consumer to receive the value.
|
|
|
|
Each handle can be used on separate tasks.
|
|
|
|
Since the `send` method is not async, it can be used anywhere. This includes
|
|
sending between two runtimes, and using it from non-async code.
|
|
|
|
If the [`Receiver`] is closed before receiving a message which has already
|
|
been sent, the message will remain in the channel until the receiver is
|
|
dropped, at which point the message will be dropped immediately.
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
if let Err(_) = tx.send(3) {
|
|
println!("the receiver dropped");
|
|
}
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(v) => println!("got = {:?}", v),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
If the sender is dropped without sending, the receiver will fail with
|
|
[`error::RecvError`]:
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel::<u32>();
|
|
|
|
tokio::spawn(async move {
|
|
drop(tx);
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(_) => panic!("This doesn't happen"),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
To use a `oneshot` channel in a `tokio::select!` loop, add `&mut` in front of
|
|
the channel.
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
use tokio::time::{interval, sleep, Duration};
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn _doc() {}
|
|
# #[tokio::main(flavor = "current_thread", start_paused = true)]
|
|
# async fn main() {
|
|
let (send, mut recv) = oneshot::channel();
|
|
let mut interval = interval(Duration::from_millis(100));
|
|
|
|
# let handle =
|
|
tokio::spawn(async move {
|
|
sleep(Duration::from_secs(1)).await;
|
|
send.send("shut down").unwrap();
|
|
});
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = interval.tick() => println!("Another 100ms"),
|
|
msg = &mut recv => {
|
|
println!("Got message: {}", msg.unwrap());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
# handle.await.unwrap();
|
|
# }
|
|
```
|
|
|
|
To use a `Sender` from a destructor, put it in an [`Option`] and call
|
|
[`Option::take`].
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
struct SendOnDrop {
|
|
sender: Option<oneshot::Sender<&'static str>>,
|
|
}
|
|
impl Drop for SendOnDrop {
|
|
fn drop(&mut self) {
|
|
if let Some(sender) = self.sender.take() {
|
|
// Using `let _ =` to ignore send errors.
|
|
let _ = sender.send("I got dropped!");
|
|
}
|
|
}
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn _doc() {}
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (send, recv) = oneshot::channel();
|
|
|
|
let send_on_drop = SendOnDrop { sender: Some(send) };
|
|
drop(send_on_drop);
|
|
|
|
assert_eq!(recv.await, Ok("I got dropped!"));
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub mod oneshot { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `error`
|
|
|
|
`Oneshot` error types.
|
|
|
|
```rust
|
|
pub mod error { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `RecvError`
|
|
|
|
Error returned by the `Future` implementation for `Receiver`.
|
|
|
|
This error is returned by the receiver when the sender is dropped without sending.
|
|
|
|
```rust
|
|
pub struct RecvError(/* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> RecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &RecvError) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Enum `TryRecvError`
|
|
|
|
Error returned by the `try_recv` function on `Receiver`.
|
|
|
|
```rust
|
|
pub enum TryRecvError {
|
|
Empty,
|
|
Closed,
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
###### `Empty`
|
|
|
|
The send half of the channel has not yet sent a value.
|
|
|
|
###### `Closed`
|
|
|
|
The send half of the channel was dropped without sending a value.
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> TryRecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Types
|
|
|
|
#### Struct `Sender`
|
|
|
|
Sends a value to the associated [`Receiver`].
|
|
|
|
A pair of both a [`Sender`] and a [`Receiver`] are created by the
|
|
[`channel`](fn@channel) function.
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
if let Err(_) = tx.send(3) {
|
|
println!("the receiver dropped");
|
|
}
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(v) => println!("got = {:?}", v),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
If the sender is dropped without sending, the receiver will fail with
|
|
[`error::RecvError`]:
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel::<u32>();
|
|
|
|
tokio::spawn(async move {
|
|
drop(tx);
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(_) => panic!("This doesn't happen"),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
To use a `Sender` from a destructor, put it in an [`Option`] and call
|
|
[`Option::take`].
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
struct SendOnDrop {
|
|
sender: Option<oneshot::Sender<&'static str>>,
|
|
}
|
|
impl Drop for SendOnDrop {
|
|
fn drop(&mut self) {
|
|
if let Some(sender) = self.sender.take() {
|
|
// Using `let _ =` to ignore send errors.
|
|
let _ = sender.send("I got dropped!");
|
|
}
|
|
}
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn _doc() {}
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (send, recv) = oneshot::channel();
|
|
|
|
let send_on_drop = SendOnDrop { sender: Some(send) };
|
|
drop(send_on_drop);
|
|
|
|
assert_eq!(recv.await, Ok("I got dropped!"));
|
|
# }
|
|
```
|
|
|
|
[`Option`]: std::option::Option
|
|
[`Option::take`]: std::option::Option::take
|
|
|
|
```rust
|
|
pub struct Sender<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn send(self: Self, t: T) -> Result<(), T> { /* ... */ }
|
|
```
|
|
Attempts to send a value on this channel, returning it back if it could
|
|
|
|
- ```rust
|
|
pub async fn closed(self: &mut Self) { /* ... */ }
|
|
```
|
|
Waits for the associated [`Receiver`] handle to close.
|
|
|
|
- ```rust
|
|
pub fn is_closed(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if the associated [`Receiver`] handle has been dropped.
|
|
|
|
- ```rust
|
|
pub fn poll_closed(self: &mut Self, cx: &mut Context<''_>) -> Poll<()> { /* ... */ }
|
|
```
|
|
Checks whether the `oneshot` channel has been closed, and if not, schedules the
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Receiver`
|
|
|
|
Receives a value from the associated [`Sender`].
|
|
|
|
A pair of both a [`Sender`] and a [`Receiver`] are created by the
|
|
[`channel`](fn@channel) function.
|
|
|
|
This channel has no `recv` method because the receiver itself implements the
|
|
[`Future`] trait. To receive a `Result<T, `[`error::RecvError`]`>`, `.await` the `Receiver` object directly.
|
|
|
|
The `poll` method on the `Future` trait is allowed to spuriously return
|
|
`Poll::Pending` even if the message has been sent. If such a spurious
|
|
failure happens, then the caller will be woken when the spurious failure has
|
|
been resolved so that the caller can attempt to receive the message again.
|
|
Note that receiving such a wakeup does not guarantee that the next call will
|
|
succeed — it could fail with another spurious failure. (A spurious failure
|
|
does not mean that the message is lost. It is just delayed.)
|
|
|
|
[`Future`]: trait@std::future::Future
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
if let Err(_) = tx.send(3) {
|
|
println!("the receiver dropped");
|
|
}
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(v) => println!("got = {:?}", v),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
If the sender is dropped without sending, the receiver will fail with
|
|
[`error::RecvError`]:
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel::<u32>();
|
|
|
|
tokio::spawn(async move {
|
|
drop(tx);
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(_) => panic!("This doesn't happen"),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
To use a `Receiver` in a `tokio::select!` loop, add `&mut` in front of the
|
|
channel.
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
use tokio::time::{interval, sleep, Duration};
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn _doc() {}
|
|
# #[tokio::main(flavor = "current_thread", start_paused = true)]
|
|
# async fn main() {
|
|
let (send, mut recv) = oneshot::channel();
|
|
let mut interval = interval(Duration::from_millis(100));
|
|
|
|
# let handle =
|
|
tokio::spawn(async move {
|
|
sleep(Duration::from_secs(1)).await;
|
|
send.send("shut down").unwrap();
|
|
});
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = interval.tick() => println!("Another 100ms"),
|
|
msg = &mut recv => {
|
|
println!("Got message: {}", msg.unwrap());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
# handle.await.unwrap();
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub struct Receiver<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn close(self: &mut Self) { /* ... */ }
|
|
```
|
|
Prevents the associated [`Sender`] handle from sending a value.
|
|
|
|
- ```rust
|
|
pub fn is_terminated(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Checks if this receiver is terminated.
|
|
|
|
- ```rust
|
|
pub fn is_empty(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Checks if a channel is empty.
|
|
|
|
- ```rust
|
|
pub fn try_recv(self: &mut Self) -> Result<T, TryRecvError> { /* ... */ }
|
|
```
|
|
Attempts to receive a value.
|
|
|
|
- ```rust
|
|
pub fn blocking_recv(self: Self) -> Result<T, RecvError> { /* ... */ }
|
|
```
|
|
Blocking receive to call outside of asynchronous contexts.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Future**
|
|
- ```rust
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<<Self as >::Output> { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **IntoFuture**
|
|
- ```rust
|
|
fn into_future(self: Self) -> <F as IntoFuture>::IntoFuture { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `channel`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[attr = TrackCaller]")`
|
|
|
|
Creates a new one-shot channel for sending single values across asynchronous
|
|
tasks.
|
|
|
|
The function returns separate "send" and "receive" handles. The `Sender`
|
|
handle is used by the producer to send the value. The `Receiver` handle is
|
|
used by the consumer to receive the value.
|
|
|
|
Each handle can be used on separate tasks.
|
|
|
|
# Examples
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
if let Err(_) = tx.send(3) {
|
|
println!("the receiver dropped");
|
|
}
|
|
});
|
|
|
|
match rx.await {
|
|
Ok(v) => println!("got = {:?}", v),
|
|
Err(_) => println!("the sender dropped"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub fn channel<T>() -> (Sender<T>, Receiver<T>) { /* ... */ }
|
|
```
|
|
|
|
## Module `watch`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
- `Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")`
|
|
|
|
A multi-producer, multi-consumer channel that only retains the *last* sent
|
|
value.
|
|
|
|
This channel is useful for watching for changes to a value from multiple
|
|
points in the code base, for example, changes to configuration values.
|
|
|
|
# Usage
|
|
|
|
[`channel`] returns a [`Sender`] / [`Receiver`] pair. These are the producer
|
|
and consumer halves of the channel. The channel is created with an initial
|
|
value.
|
|
|
|
Each [`Receiver`] independently tracks the last value *seen* by its caller.
|
|
|
|
To access the **current** value stored in the channel and mark it as *seen*
|
|
by a given [`Receiver`], use [`Receiver::borrow_and_update()`].
|
|
|
|
To access the current value **without** marking it as *seen*, use
|
|
[`Receiver::borrow()`]. (If the value has already been marked *seen*,
|
|
[`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
|
|
|
|
For more information on when to use these methods, see
|
|
[here](#borrow_and_update-versus-borrow).
|
|
|
|
## Change notifications
|
|
|
|
The [`Receiver`] half provides an asynchronous [`changed`] method. This
|
|
method is ready when a new, *unseen* value is sent via the [`Sender`] half.
|
|
|
|
* [`Receiver::changed()`] returns:
|
|
* `Ok(())` on receiving a new value.
|
|
* `Err(`[`RecvError`](error::RecvError)`)` if the
|
|
channel has been closed __AND__ the current value is *seen*.
|
|
* If the current value is *unseen* when calling [`changed`], then
|
|
[`changed`] will return immediately. If the current value is *seen*, then
|
|
it will sleep until either a new message is sent via the [`Sender`] half,
|
|
or the [`Sender`] is dropped.
|
|
* On completion, the [`changed`] method marks the new value as *seen*.
|
|
* At creation, the initial value is considered *seen*. In other words,
|
|
[`Receiver::changed()`] will not return until a subsequent value is sent.
|
|
* New [`Receiver`] instances can be created with [`Sender::subscribe()`].
|
|
The current value at the time the [`Receiver`] is created is considered
|
|
*seen*.
|
|
|
|
## [`changed`] versus [`has_changed`]
|
|
|
|
The [`Receiver`] half provides two methods for checking for changes
|
|
in the channel, [`has_changed`] and [`changed`].
|
|
|
|
* [`has_changed`] is a *synchronous* method that checks whether the current
|
|
value is seen or not and returns a boolean. This method does __not__ mark the
|
|
value as seen.
|
|
|
|
* [`changed`] is an *asynchronous* method that will return once an unseen
|
|
value is in the channel. This method does mark the value as seen.
|
|
|
|
Note there are two behavioral differences on when these two methods return
|
|
an error.
|
|
|
|
- [`has_changed`] errors if and only if the channel is closed.
|
|
- [`changed`] errors if the channel has been closed __AND__
|
|
the current value is seen.
|
|
|
|
See the example below that shows how these methods have different fallibility.
|
|
|
|
## [`borrow_and_update`] versus [`borrow`]
|
|
|
|
If the receiver intends to await notifications from [`changed`] in a loop,
|
|
[`Receiver::borrow_and_update()`] should be preferred over
|
|
[`Receiver::borrow()`]. This avoids a potential race where a new value is
|
|
sent between [`changed`] being ready and the value being read. (If
|
|
[`Receiver::borrow()`] is used, the loop may run twice with the same value.)
|
|
|
|
If the receiver is only interested in the current value, and does not intend
|
|
to wait for changes, then [`Receiver::borrow()`] can be used. It may be more
|
|
convenient to use [`borrow`](Receiver::borrow) since it's an `&self`
|
|
method---[`borrow_and_update`](Receiver::borrow_and_update) requires `&mut
|
|
self`.
|
|
|
|
# Examples
|
|
|
|
The following example prints `hello! world! `.
|
|
|
|
```
|
|
use tokio::sync::watch;
|
|
use tokio::time::{Duration, sleep};
|
|
|
|
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
|
let (tx, mut rx) = watch::channel("hello");
|
|
|
|
tokio::spawn(async move {
|
|
// Use the equivalent of a "do-while" loop so the initial value is
|
|
// processed before awaiting the `changed()` future.
|
|
loop {
|
|
println!("{}! ", *rx.borrow_and_update());
|
|
if rx.changed().await.is_err() {
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
tx.send("world")?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
Difference on fallibility of [`changed`] versus [`has_changed`].
|
|
```
|
|
use tokio::sync::watch;
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx, mut rx) = watch::channel("hello");
|
|
tx.send("goodbye").unwrap();
|
|
drop(tx);
|
|
|
|
// `has_changed` does not mark the value as seen and errors
|
|
// since the channel is closed.
|
|
assert!(rx.has_changed().is_err());
|
|
|
|
// `changed` returns Ok since the value is not already marked as seen
|
|
// even if the channel is closed.
|
|
assert!(rx.changed().await.is_ok());
|
|
|
|
// The `changed` call above marks the value as seen.
|
|
// The next `changed` call now returns an error as the channel is closed
|
|
// AND the current value is seen.
|
|
assert!(rx.changed().await.is_err());
|
|
# }
|
|
```
|
|
|
|
# Closing
|
|
|
|
[`Sender::is_closed`] and [`Sender::closed`] allow the producer to detect
|
|
when all [`Receiver`] handles have been dropped. This indicates that there
|
|
is no further interest in the values being produced and work can be stopped.
|
|
|
|
The value in the channel will not be dropped until all senders and all
|
|
receivers have been dropped.
|
|
|
|
# Thread safety
|
|
|
|
Both [`Sender`] and [`Receiver`] are thread safe. They can be moved to other
|
|
threads and can be used in a concurrent environment. Clones of [`Receiver`]
|
|
handles may be moved to separate threads and also used concurrently.
|
|
|
|
[`Sender`]: crate::sync::watch::Sender
|
|
[`Receiver`]: crate::sync::watch::Receiver
|
|
[`changed`]: crate::sync::watch::Receiver::changed
|
|
[`has_changed`]: crate::sync::watch::Receiver::has_changed
|
|
[`borrow`]: crate::sync::watch::Receiver::borrow
|
|
[`borrow_and_update`]: crate::sync::watch::Receiver::borrow_and_update
|
|
[`Receiver::changed()`]: crate::sync::watch::Receiver::changed
|
|
[`Receiver::borrow()`]: crate::sync::watch::Receiver::borrow
|
|
[`Receiver::borrow_and_update()`]:
|
|
crate::sync::watch::Receiver::borrow_and_update
|
|
[`channel`]: crate::sync::watch::channel
|
|
[`Sender::is_closed`]: crate::sync::watch::Sender::is_closed
|
|
[`Sender::closed`]: crate::sync::watch::Sender::closed
|
|
[`Sender::subscribe()`]: crate::sync::watch::Sender::subscribe
|
|
|
|
```rust
|
|
pub mod watch { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `error`
|
|
|
|
Watch error types.
|
|
|
|
```rust
|
|
pub mod error { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `SendError`
|
|
|
|
Error produced when sending a value fails.
|
|
|
|
```rust
|
|
pub struct SendError<T>(pub T);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `T` | |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> SendError<T> { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &SendError<T>) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `RecvError`
|
|
|
|
Error produced when receiving a change notification.
|
|
|
|
```rust
|
|
pub struct RecvError(/* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> RecvError { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Types
|
|
|
|
#### Struct `Receiver`
|
|
|
|
Receives values from the associated [`Sender`](struct@Sender).
|
|
|
|
Instances are created by the [`channel`](fn@channel) function.
|
|
|
|
To turn this receiver into a `Stream`, you can use the [`WatchStream`]
|
|
wrapper.
|
|
|
|
[`WatchStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.WatchStream.html
|
|
|
|
```rust
|
|
pub struct Receiver<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn borrow(self: &Self) -> Ref<''_, T> { /* ... */ }
|
|
```
|
|
Returns a reference to the most recently sent value.
|
|
|
|
- ```rust
|
|
pub fn borrow_and_update(self: &mut Self) -> Ref<''_, T> { /* ... */ }
|
|
```
|
|
Returns a reference to the most recently sent value and marks that value
|
|
|
|
- ```rust
|
|
pub fn has_changed(self: &Self) -> Result<bool, error::RecvError> { /* ... */ }
|
|
```
|
|
Checks if this channel contains a message that this receiver has not yet
|
|
|
|
- ```rust
|
|
pub fn mark_changed(self: &mut Self) { /* ... */ }
|
|
```
|
|
Marks the state as changed.
|
|
|
|
- ```rust
|
|
pub fn mark_unchanged(self: &mut Self) { /* ... */ }
|
|
```
|
|
Marks the state as unchanged.
|
|
|
|
- ```rust
|
|
pub async fn changed(self: &mut Self) -> Result<(), error::RecvError> { /* ... */ }
|
|
```
|
|
Waits for a change notification, then marks the current value as seen.
|
|
|
|
- ```rust
|
|
pub async fn wait_for</* synthetic */ impl FnMut(&T) -> bool: FnMut(&T) -> bool>(self: &mut Self, f: impl FnMut(&T) -> bool) -> Result<Ref<''_, T>, error::RecvError> { /* ... */ }
|
|
```
|
|
Waits for a value that satisfies the provided condition.
|
|
|
|
- ```rust
|
|
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if receivers belong to the same channel.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> Self { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Sender`
|
|
|
|
Sends values to the associated [`Receiver`](struct@Receiver).
|
|
|
|
Instances are created by the [`channel`](fn@channel) function.
|
|
|
|
```rust
|
|
pub struct Sender<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new(init: T) -> Self { /* ... */ }
|
|
```
|
|
Creates the sending-half of the [`watch`] channel.
|
|
|
|
- ```rust
|
|
pub fn send(self: &Self, value: T) -> Result<(), error::SendError<T>> { /* ... */ }
|
|
```
|
|
Sends a new value via the channel, notifying all receivers.
|
|
|
|
- ```rust
|
|
pub fn send_modify<F>(self: &Self, modify: F)
|
|
where
|
|
F: FnOnce(&mut T) { /* ... */ }
|
|
```
|
|
Modifies the watched value **unconditionally** in-place,
|
|
|
|
- ```rust
|
|
pub fn send_if_modified<F>(self: &Self, modify: F) -> bool
|
|
where
|
|
F: FnOnce(&mut T) -> bool { /* ... */ }
|
|
```
|
|
Modifies the watched value **conditionally** in-place,
|
|
|
|
- ```rust
|
|
pub fn send_replace(self: &Self, value: T) -> T { /* ... */ }
|
|
```
|
|
Sends a new value via the channel, notifying all receivers and returning
|
|
|
|
- ```rust
|
|
pub fn borrow(self: &Self) -> Ref<''_, T> { /* ... */ }
|
|
```
|
|
Returns a reference to the most recently sent value
|
|
|
|
- ```rust
|
|
pub fn is_closed(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Checks if the channel has been closed. This happens when all receivers
|
|
|
|
- ```rust
|
|
pub async fn closed(self: &Self) { /* ... */ }
|
|
```
|
|
Completes when all receivers have dropped.
|
|
|
|
- ```rust
|
|
pub fn subscribe(self: &Self) -> Receiver<T> { /* ... */ }
|
|
```
|
|
Creates a new [`Receiver`] connected to this `Sender`.
|
|
|
|
- ```rust
|
|
pub fn receiver_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of receivers that currently exist.
|
|
|
|
- ```rust
|
|
pub fn sender_count(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of senders that currently exist.
|
|
|
|
- ```rust
|
|
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if senders belong to the same channel.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> Self { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Default**
|
|
- ```rust
|
|
fn default() -> Self { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Ref`
|
|
|
|
Returns a reference to the inner value.
|
|
|
|
Outstanding borrows hold a read lock on the inner value. This means that
|
|
long-lived borrows could cause the producer half to block. It is recommended
|
|
to keep the borrow as short-lived as possible. Additionally, if you are
|
|
running in an environment that allows `!Send` futures, you must ensure that
|
|
the returned `Ref` type is never held alive across an `.await` point,
|
|
otherwise, it can lead to a deadlock.
|
|
|
|
The priority policy of the lock is dependent on the underlying lock
|
|
implementation, and this type does not guarantee that any particular policy
|
|
will be used. In particular, a producer which is waiting to acquire the lock
|
|
in `send` might or might not block concurrent calls to `borrow`, e.g.:
|
|
|
|
<details><summary>Potential deadlock example</summary>
|
|
|
|
```text
|
|
// Task 1 (on thread A) | // Task 2 (on thread B)
|
|
let _ref1 = rx.borrow(); |
|
|
| // will block
|
|
| let _ = tx.send(());
|
|
// may deadlock |
|
|
let _ref2 = rx.borrow(); |
|
|
```
|
|
</details>
|
|
|
|
```rust
|
|
pub struct Ref<''a, T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn has_changed(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Indicates if the borrowed value is considered as _changed_ since the last
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Deref**
|
|
- ```rust
|
|
fn deref(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **Receiver**
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `channel`
|
|
|
|
Creates a new watch channel, returning the "send" and "receive" handles.
|
|
|
|
All values sent by [`Sender`] will become visible to the [`Receiver`] handles.
|
|
Only the last value sent is made available to the [`Receiver`] half. All
|
|
intermediate values are dropped.
|
|
|
|
# Examples
|
|
|
|
The following example prints `hello! world! `.
|
|
|
|
```
|
|
use tokio::sync::watch;
|
|
use tokio::time::{Duration, sleep};
|
|
|
|
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
|
|
let (tx, mut rx) = watch::channel("hello");
|
|
|
|
tokio::spawn(async move {
|
|
// Use the equivalent of a "do-while" loop so the initial value is
|
|
// processed before awaiting the `changed()` future.
|
|
loop {
|
|
println!("{}! ", *rx.borrow_and_update());
|
|
if rx.changed().await.is_err() {
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
tx.send("world")?;
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
[`Sender`]: struct@Sender
|
|
[`Receiver`]: struct@Receiver
|
|
|
|
```rust
|
|
pub fn channel<T>(init: T) -> (Sender<T>, Receiver<T>) { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `Barrier`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use barrier::Barrier;
|
|
```
|
|
|
|
#### Re-export `BarrierWaitResult`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use barrier::BarrierWaitResult;
|
|
```
|
|
|
|
#### Re-export `Mutex`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::Mutex;
|
|
```
|
|
|
|
#### Re-export `MutexGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::MutexGuard;
|
|
```
|
|
|
|
#### Re-export `TryLockError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::TryLockError;
|
|
```
|
|
|
|
#### Re-export `OwnedMutexGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::OwnedMutexGuard;
|
|
```
|
|
|
|
#### Re-export `MappedMutexGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::MappedMutexGuard;
|
|
```
|
|
|
|
#### Re-export `OwnedMappedMutexGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use mutex::OwnedMappedMutexGuard;
|
|
```
|
|
|
|
#### Re-export `Notify`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use notify::Notify;
|
|
```
|
|
|
|
#### Re-export `AcquireError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use batch_semaphore::AcquireError;
|
|
```
|
|
|
|
#### Re-export `TryAcquireError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use batch_semaphore::TryAcquireError;
|
|
```
|
|
|
|
#### Re-export `Semaphore`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use semaphore::Semaphore;
|
|
```
|
|
|
|
#### Re-export `SemaphorePermit`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use semaphore::SemaphorePermit;
|
|
```
|
|
|
|
#### Re-export `OwnedSemaphorePermit`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use semaphore::OwnedSemaphorePermit;
|
|
```
|
|
|
|
#### Re-export `RwLock`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::RwLock;
|
|
```
|
|
|
|
#### Re-export `OwnedRwLockReadGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::owned_read_guard::OwnedRwLockReadGuard;
|
|
```
|
|
|
|
#### Re-export `OwnedRwLockWriteGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::owned_write_guard::OwnedRwLockWriteGuard;
|
|
```
|
|
|
|
#### Re-export `OwnedRwLockMappedWriteGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::owned_write_guard_mapped::OwnedRwLockMappedWriteGuard;
|
|
```
|
|
|
|
#### Re-export `RwLockReadGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::read_guard::RwLockReadGuard;
|
|
```
|
|
|
|
#### Re-export `RwLockWriteGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::write_guard::RwLockWriteGuard;
|
|
```
|
|
|
|
#### Re-export `RwLockMappedWriteGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use rwlock::write_guard_mapped::RwLockMappedWriteGuard;
|
|
```
|
|
|
|
#### Re-export `OnceCell`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use self::once_cell::OnceCell;
|
|
```
|
|
|
|
#### Re-export `SetError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use self::once_cell::SetError;
|
|
```
|
|
|
|
#### Re-export `SetOnce`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use self::set_once::SetOnce;
|
|
```
|
|
|
|
#### Re-export `SetOnceError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"sync\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"sync\"))]")`
|
|
|
|
```rust
|
|
pub use self::set_once::SetOnceError;
|
|
```
|
|
|
|
## Module `task`
|
|
|
|
Asynchronous green-threads.
|
|
|
|
## What are Tasks?
|
|
|
|
A _task_ is a light weight, non-blocking unit of execution. A task is similar
|
|
to an OS thread, but rather than being managed by the OS scheduler, they are
|
|
managed by the [Tokio runtime][rt]. Another name for this general pattern is
|
|
[green threads]. If you are familiar with [Go's goroutines], [Kotlin's
|
|
coroutines], or [Erlang's processes], you can think of Tokio's tasks as
|
|
something similar.
|
|
|
|
Key points about tasks include:
|
|
|
|
* Tasks are **light weight**. Because tasks are scheduled by the Tokio
|
|
runtime rather than the operating system, creating new tasks or switching
|
|
between tasks does not require a context switch and has fairly low
|
|
overhead. Creating, running, and destroying large numbers of tasks is
|
|
quite cheap, especially compared to OS threads.
|
|
|
|
* Tasks are scheduled **cooperatively**. Most operating systems implement
|
|
_preemptive multitasking_. This is a scheduling technique where the
|
|
operating system allows each thread to run for a period of time, and then
|
|
_preempts_ it, temporarily pausing that thread and switching to another.
|
|
Tasks, on the other hand, implement _cooperative multitasking_. In
|
|
cooperative multitasking, a task is allowed to run until it _yields_,
|
|
indicating to the Tokio runtime's scheduler that it cannot currently
|
|
continue executing. When a task yields, the Tokio runtime switches to
|
|
executing the next task.
|
|
|
|
* Tasks are **non-blocking**. Typically, when an OS thread performs I/O or
|
|
must synchronize with another thread, it _blocks_, allowing the OS to
|
|
schedule another thread. When a task cannot continue executing, it must
|
|
yield instead, allowing the Tokio runtime to schedule another task. Tasks
|
|
should generally not perform system calls or other operations that could
|
|
block a thread, as this would prevent other tasks running on the same
|
|
thread from executing as well. Instead, this module provides APIs for
|
|
running blocking operations in an asynchronous context.
|
|
|
|
[rt]: crate::runtime
|
|
[green threads]: https://en.wikipedia.org/wiki/Green_threads
|
|
[Go's goroutines]: https://tour.golang.org/concurrency/1
|
|
[Kotlin's coroutines]: https://kotlinlang.org/docs/reference/coroutines-overview.html
|
|
[Erlang's processes]: http://erlang.org/doc/getting_started/conc_prog.html#processes
|
|
|
|
## Working with Tasks
|
|
|
|
This module provides the following APIs for working with tasks:
|
|
|
|
### Spawning
|
|
|
|
Perhaps the most important function in this module is [`task::spawn`]. This
|
|
function can be thought of as an async equivalent to the standard library's
|
|
[`thread::spawn`][`std::thread::spawn`]. It takes an `async` block or other
|
|
[future], and creates a new task to run that work concurrently:
|
|
|
|
```
|
|
use tokio::task;
|
|
|
|
# async fn doc() {
|
|
task::spawn(async {
|
|
// perform some work here...
|
|
});
|
|
# }
|
|
```
|
|
|
|
Like [`std::thread::spawn`], `task::spawn` returns a [`JoinHandle`] struct.
|
|
A `JoinHandle` is itself a future which may be used to await the output of
|
|
the spawned task. For example:
|
|
|
|
```
|
|
use tokio::task;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let join = task::spawn(async {
|
|
// ...
|
|
"hello world!"
|
|
});
|
|
|
|
// ...
|
|
|
|
// Await the result of the spawned task.
|
|
let result = join.await?;
|
|
assert_eq!(result, "hello world!");
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
Again, like `std::thread`'s [`JoinHandle` type][thread_join], if the spawned
|
|
task panics, awaiting its `JoinHandle` will return a [`JoinError`]. For
|
|
example:
|
|
|
|
```
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::task;
|
|
|
|
# #[tokio::main] async fn main() {
|
|
let join = task::spawn(async {
|
|
panic!("something bad happened!")
|
|
});
|
|
|
|
// The returned result indicates that the task failed.
|
|
assert!(join.await.is_err());
|
|
# }
|
|
# }
|
|
```
|
|
|
|
`spawn`, `JoinHandle`, and `JoinError` are present when the "rt"
|
|
feature flag is enabled.
|
|
|
|
[`task::spawn`]: crate::task::spawn()
|
|
[future]: std::future::Future
|
|
[`std::thread::spawn`]: std::thread::spawn
|
|
[`JoinHandle`]: crate::task::JoinHandle
|
|
[thread_join]: std::thread::JoinHandle
|
|
[`JoinError`]: crate::task::JoinError
|
|
|
|
#### Cancellation
|
|
|
|
Spawned tasks may be cancelled using the [`JoinHandle::abort`] or
|
|
[`AbortHandle::abort`] methods. When one of these methods are called, the
|
|
task is signalled to shut down next time it yields at an `.await` point. If
|
|
the task is already idle, then it will be shut down as soon as possible
|
|
without running again before being shut down. Additionally, shutting down a
|
|
Tokio runtime (e.g. by returning from `#[tokio::main]`) immediately cancels
|
|
all tasks on it.
|
|
|
|
When tasks are shut down, it will stop running at whichever `.await` it has
|
|
yielded at. All local variables are destroyed by running their destructor.
|
|
Once shutdown has completed, awaiting the [`JoinHandle`] will fail with a
|
|
[cancelled error](crate::task::JoinError::is_cancelled).
|
|
|
|
Note that aborting a task does not guarantee that it fails with a cancelled
|
|
error, since it may complete normally first. For example, if the task does
|
|
not yield to the runtime at any point between the call to `abort` and the
|
|
end of the task, then the [`JoinHandle`] will instead report that the task
|
|
exited normally.
|
|
|
|
Be aware that tasks spawned using [`spawn_blocking`] cannot be aborted
|
|
because they are not async. If you call `abort` on a `spawn_blocking`
|
|
task, then this *will not have any effect*, and the task will continue
|
|
running normally. The exception is if the task has not started running
|
|
yet; in that case, calling `abort` may prevent the task from starting.
|
|
|
|
Be aware that calls to [`JoinHandle::abort`] just schedule the task for
|
|
cancellation, and will return before the cancellation has completed. To wait
|
|
for cancellation to complete, wait for the task to finish by awaiting the
|
|
[`JoinHandle`]. Similarly, the [`JoinHandle::is_finished`] method does not
|
|
return `true` until the cancellation has finished.
|
|
|
|
Calling [`JoinHandle::abort`] multiple times has the same effect as calling
|
|
it once.
|
|
|
|
Tokio also provides an [`AbortHandle`], which is like the [`JoinHandle`],
|
|
except that it does not provide a mechanism to wait for the task to finish.
|
|
Each task can only have one [`JoinHandle`], but it can have more than one
|
|
[`AbortHandle`].
|
|
|
|
[`JoinHandle::abort`]: crate::task::JoinHandle::abort
|
|
[`AbortHandle::abort`]: crate::task::AbortHandle::abort
|
|
[`AbortHandle`]: crate::task::AbortHandle
|
|
[`JoinHandle::is_finished`]: crate::task::JoinHandle::is_finished
|
|
|
|
### Blocking and Yielding
|
|
|
|
As we discussed above, code running in asynchronous tasks should not perform
|
|
operations that can block. A blocking operation performed in a task running
|
|
on a thread that is also running other tasks would block the entire thread,
|
|
preventing other tasks from running.
|
|
|
|
Instead, Tokio provides two APIs for running blocking operations in an
|
|
asynchronous context: [`task::spawn_blocking`] and [`task::block_in_place`].
|
|
|
|
Be aware that if you call a non-async method from async code, that non-async
|
|
method is still inside the asynchronous context, so you should also avoid
|
|
blocking operations there. This includes destructors of objects destroyed in
|
|
async code.
|
|
|
|
#### `spawn_blocking`
|
|
|
|
The `task::spawn_blocking` function is similar to the `task::spawn` function
|
|
discussed in the previous section, but rather than spawning an
|
|
_non-blocking_ future on the Tokio runtime, it instead spawns a
|
|
_blocking_ function on a dedicated thread pool for blocking tasks. For
|
|
example:
|
|
|
|
```
|
|
use tokio::task;
|
|
|
|
# async fn docs() {
|
|
task::spawn_blocking(|| {
|
|
// do some compute-heavy work or call synchronous code
|
|
});
|
|
# }
|
|
```
|
|
|
|
Just like `task::spawn`, `task::spawn_blocking` returns a `JoinHandle`
|
|
which we can use to await the result of the blocking operation:
|
|
|
|
```rust
|
|
# use tokio::task;
|
|
# async fn docs() -> Result<(), Box<dyn std::error::Error>>{
|
|
let join = task::spawn_blocking(|| {
|
|
// do some compute-heavy work or call synchronous code
|
|
"blocking completed"
|
|
});
|
|
|
|
let result = join.await?;
|
|
assert_eq!(result, "blocking completed");
|
|
# Ok(())
|
|
# }
|
|
```
|
|
|
|
#### `block_in_place`
|
|
|
|
When using the [multi-threaded runtime][rt-multi-thread], the [`task::block_in_place`]
|
|
function is also available. Like `task::spawn_blocking`, this function
|
|
allows running a blocking operation from an asynchronous context. Unlike
|
|
`spawn_blocking`, however, `block_in_place` works by transitioning the
|
|
_current_ worker thread to a blocking thread, moving other tasks running on
|
|
that thread to another worker thread. This can improve performance by avoiding
|
|
context switches.
|
|
|
|
For example:
|
|
|
|
```
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
use tokio::task;
|
|
|
|
# async fn docs() {
|
|
let result = task::block_in_place(|| {
|
|
// do some compute-heavy work or call synchronous code
|
|
"blocking completed"
|
|
});
|
|
|
|
assert_eq!(result, "blocking completed");
|
|
# }
|
|
# }
|
|
```
|
|
|
|
#### `yield_now`
|
|
|
|
In addition, this module provides a [`task::yield_now`] async function
|
|
that is analogous to the standard library's [`thread::yield_now`]. Calling
|
|
and `await`ing this function will cause the current task to yield to the
|
|
Tokio runtime's scheduler, allowing other tasks to be
|
|
scheduled. Eventually, the yielding task will be polled again, allowing it
|
|
to execute. For example:
|
|
|
|
```rust
|
|
use tokio::task;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
async {
|
|
task::spawn(async {
|
|
// ...
|
|
println!("spawned task done!")
|
|
});
|
|
|
|
// Yield, allowing the newly-spawned task to execute first.
|
|
task::yield_now().await;
|
|
println!("main task done!");
|
|
}
|
|
# .await;
|
|
# }
|
|
```
|
|
|
|
[`task::spawn_blocking`]: crate::task::spawn_blocking
|
|
[`task::block_in_place`]: crate::task::block_in_place
|
|
[rt-multi-thread]: ../runtime/index.html#threaded-scheduler
|
|
[`task::yield_now`]: crate::task::yield_now()
|
|
[`thread::yield_now`]: std::thread::yield_now
|
|
|
|
```rust
|
|
pub mod task { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `coop`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[<cfg_attr>(not(feature = \"full\"), allow(dead_code))]")`
|
|
- `Other("#[<cfg_attr>(not(feature = \"rt\"), allow(unreachable_pub))]")`
|
|
|
|
Utilities for improved cooperative scheduling.
|
|
|
|
### Cooperative scheduling
|
|
|
|
A single call to [`poll`] on a top-level task may potentially do a lot of
|
|
work before it returns `Poll::Pending`. If a task runs for a long period of
|
|
time without yielding back to the executor, it can starve other tasks
|
|
waiting on that executor to execute them, or drive underlying resources.
|
|
Since Rust does not have a runtime, it is difficult to forcibly preempt a
|
|
long-running task. Instead, this module provides an opt-in mechanism for
|
|
futures to collaborate with the executor to avoid starvation.
|
|
|
|
Consider a future like this one:
|
|
|
|
```
|
|
# use tokio_stream::{Stream, StreamExt};
|
|
async fn drop_all<I: Stream + Unpin>(mut input: I) {
|
|
while let Some(_) = input.next().await {}
|
|
}
|
|
```
|
|
|
|
It may look harmless, but consider what happens under heavy load if the
|
|
input stream is _always_ ready. If we spawn `drop_all`, the task will never
|
|
yield, and will starve other tasks and resources on the same executor.
|
|
|
|
To account for this, Tokio has explicit yield points in a number of library
|
|
functions, which force tasks to return to the executor periodically.
|
|
|
|
|
|
#### unconstrained
|
|
|
|
If necessary, [`task::unconstrained`] lets you opt a future out of Tokio's cooperative
|
|
scheduling. When a future is wrapped with `unconstrained`, it will never be forced to yield to
|
|
Tokio. For example:
|
|
|
|
```
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
use tokio::{task, sync::mpsc};
|
|
|
|
let fut = async {
|
|
let (tx, mut rx) = mpsc::unbounded_channel();
|
|
|
|
for i in 0..1000 {
|
|
let _ = tx.send(());
|
|
// This will always be ready. If coop was in effect, this code would be forced to yield
|
|
// periodically. However, if left unconstrained, then this code will never yield.
|
|
rx.recv().await;
|
|
}
|
|
};
|
|
|
|
task::coop::unconstrained(fut).await;
|
|
# }
|
|
```
|
|
[`poll`]: method@std::future::Future::poll
|
|
[`task::unconstrained`]: crate::task::unconstrained()
|
|
|
|
```rust
|
|
pub mod coop { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `RestoreOnPending`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")`
|
|
- `MustUse { reason: None }`
|
|
|
|
Value returned by the [`poll_proceed`] method.
|
|
|
|
```rust
|
|
pub struct RestoreOnPending(/* private field */, /* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
| 1 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn made_progress(self: &Self) { /* ... */ }
|
|
```
|
|
Signals that the task that obtained this `RestoreOnPending` was able to make
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Coop`
|
|
|
|
**Attributes:**
|
|
|
|
- `MustUse { reason: Some("futures do nothing unless polled") }`
|
|
|
|
Future wrapper to ensure cooperative scheduling created by [`cooperative`].
|
|
|
|
```rust
|
|
pub struct Coop<F: Future> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Future**
|
|
- ```rust
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<<Self as >::Output> { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **IntoFuture**
|
|
- ```rust
|
|
fn into_future(self: Self) -> <F as IntoFuture>::IntoFuture { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Functions
|
|
|
|
#### Function `has_budget_remaining`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[attr = Inline(Always)]")`
|
|
|
|
Returns `true` if there is still budget left on the task.
|
|
|
|
# Examples
|
|
|
|
This example defines a `Timeout` future that requires a given `future` to complete before the
|
|
specified duration elapses. If it does, its result is returned; otherwise, an error is returned
|
|
and the future is canceled.
|
|
|
|
Note that the future could exhaust the budget before we evaluate the timeout. Using `has_budget_remaining`,
|
|
we can detect this scenario and ensure the timeout is always checked.
|
|
|
|
```
|
|
# use std::future::Future;
|
|
# use std::pin::{pin, Pin};
|
|
# use std::task::{ready, Context, Poll};
|
|
# use tokio::task::coop;
|
|
# use tokio::time::Sleep;
|
|
pub struct Timeout<T> {
|
|
future: T,
|
|
delay: Pin<Box<Sleep>>,
|
|
}
|
|
|
|
impl<T> Future for Timeout<T>
|
|
where
|
|
T: Future + Unpin,
|
|
{
|
|
type Output = Result<T::Output, ()>;
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
let this = Pin::into_inner(self);
|
|
let future = Pin::new(&mut this.future);
|
|
let delay = Pin::new(&mut this.delay);
|
|
|
|
// check if the future is ready
|
|
let had_budget_before = coop::has_budget_remaining();
|
|
if let Poll::Ready(v) = future.poll(cx) {
|
|
return Poll::Ready(Ok(v));
|
|
}
|
|
let has_budget_now = coop::has_budget_remaining();
|
|
|
|
// evaluate the timeout
|
|
if let (true, false) = (had_budget_before, has_budget_now) {
|
|
// it is the underlying future that exhausted the budget
|
|
ready!(pin!(coop::unconstrained(delay)).poll(cx));
|
|
} else {
|
|
ready!(delay.poll(cx));
|
|
}
|
|
return Poll::Ready(Err(()));
|
|
}
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn has_budget_remaining() -> bool { /* ... */ }
|
|
```
|
|
|
|
#### Function `poll_proceed`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")`
|
|
- `Other("#[attr = Inline(Hint)]")`
|
|
|
|
Decrements the task budget and returns [`Poll::Pending`] if the budget is depleted.
|
|
This indicates that the task should yield to the scheduler. Otherwise, returns
|
|
[`RestoreOnPending`] which can be used to commit the budget consumption.
|
|
|
|
The returned [`RestoreOnPending`] will revert the budget to its former
|
|
value when dropped unless [`RestoreOnPending::made_progress`]
|
|
is called. It is the caller's responsibility to do so when it _was_ able to
|
|
make progress after the call to [`poll_proceed`].
|
|
Restoring the budget automatically ensures the task can try to make progress in some other
|
|
way.
|
|
|
|
Note that [`RestoreOnPending`] restores the budget **as it was before [`poll_proceed`]**.
|
|
Therefore, if the budget is _further_ adjusted between when [`poll_proceed`] returns and
|
|
[`RestoreOnPending`] is dropped, those adjustments are erased unless the caller indicates
|
|
that progress was made.
|
|
|
|
# Examples
|
|
|
|
This example wraps the `futures::channel::mpsc::UnboundedReceiver` to
|
|
cooperate with the Tokio scheduler. Each time a value is received, task budget
|
|
is consumed. If no budget is available, the task yields to the scheduler.
|
|
|
|
```
|
|
use std::pin::Pin;
|
|
use std::task::{ready, Context, Poll};
|
|
use tokio::task::coop;
|
|
use futures::stream::{Stream, StreamExt};
|
|
use futures::channel::mpsc::UnboundedReceiver;
|
|
|
|
struct CoopUnboundedReceiver<T> {
|
|
receiver: UnboundedReceiver<T>,
|
|
}
|
|
|
|
impl<T> Stream for CoopUnboundedReceiver<T> {
|
|
type Item = T;
|
|
fn poll_next(
|
|
mut self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>
|
|
) -> Poll<Option<T>> {
|
|
let coop = ready!(coop::poll_proceed(cx));
|
|
match self.receiver.poll_next_unpin(cx) {
|
|
Poll::Ready(v) => {
|
|
// We received a value, so consume budget.
|
|
coop.made_progress();
|
|
Poll::Ready(v)
|
|
}
|
|
Poll::Pending => Poll::Pending,
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
```rust
|
|
pub fn poll_proceed(cx: &mut std::task::Context<''_>) -> std::task::Poll<RestoreOnPending> { /* ... */ }
|
|
```
|
|
|
|
#### Function `cooperative`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")`
|
|
- `Other("#[attr = Inline(Hint)]")`
|
|
|
|
Creates a wrapper future that makes the inner future cooperate with the Tokio scheduler.
|
|
|
|
When polled, the wrapper will first call [`poll_proceed`] to consume task budget, and
|
|
immediately yield if the budget has been depleted. If budget was available, the inner future
|
|
is polled. The budget consumption will be made final using [`RestoreOnPending::made_progress`]
|
|
if the inner future resolves to its final value.
|
|
|
|
# Examples
|
|
|
|
When you call `recv` on the `Receiver` of a [`tokio::sync::mpsc`](crate::sync::mpsc)
|
|
channel, task budget will automatically be consumed when the next value is returned.
|
|
This makes tasks that use Tokio mpsc channels automatically cooperative.
|
|
|
|
If you're using [`futures::channel::mpsc`](https://docs.rs/futures/latest/futures/channel/mpsc/index.html)
|
|
instead, automatic task budget consumption will not happen. This example shows how can use
|
|
`cooperative` to make `futures::channel::mpsc` channels cooperate with the scheduler in the
|
|
same way Tokio channels do.
|
|
|
|
```
|
|
use tokio::task::coop::cooperative;
|
|
use futures::channel::mpsc::Receiver;
|
|
use futures::stream::StreamExt;
|
|
|
|
async fn receive_next<T>(receiver: &mut Receiver<T>) -> Option<T> {
|
|
// Use `StreamExt::next` to obtain a `Future` that resolves to the next value
|
|
let recv_future = receiver.next();
|
|
// Wrap it a cooperative wrapper
|
|
let coop_future = cooperative(recv_future);
|
|
// And await
|
|
coop_future.await
|
|
}
|
|
|
|
```rust
|
|
pub fn cooperative<F: Future>(fut: F) -> Coop<F> { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `consume_budget`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use consume_budget::consume_budget;
|
|
```
|
|
|
|
#### Re-export `unconstrained`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use unconstrained::unconstrained;
|
|
```
|
|
|
|
#### Re-export `Unconstrained`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use unconstrained::Unconstrained;
|
|
```
|
|
|
|
## Module `join_set`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[<cfg>(tokio_unstable)]")`
|
|
|
|
A collection of tasks spawned on a Tokio runtime.
|
|
|
|
This module provides the [`JoinSet`] type, a collection which stores a set
|
|
of spawned tasks and allows asynchronously awaiting the output of those
|
|
tasks as they complete. See the documentation for the [`JoinSet`] type for
|
|
details.
|
|
|
|
```rust
|
|
pub mod join_set { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `JoinSet`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
A collection of tasks spawned on a Tokio runtime.
|
|
|
|
A `JoinSet` can be used to await the completion of some or all of the tasks
|
|
in the set. The set is not ordered, and the tasks will be returned in the
|
|
order they complete.
|
|
|
|
All of the tasks must have the same return type `T`.
|
|
|
|
When the `JoinSet` is dropped, all tasks in the `JoinSet` are immediately aborted.
|
|
|
|
# Examples
|
|
|
|
Spawn multiple tasks and wait for them.
|
|
|
|
```
|
|
use tokio::task::JoinSet;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut set = JoinSet::new();
|
|
|
|
for i in 0..10 {
|
|
set.spawn(async move { i });
|
|
}
|
|
|
|
let mut seen = [false; 10];
|
|
while let Some(res) = set.join_next().await {
|
|
let idx = res.unwrap();
|
|
seen[idx] = true;
|
|
}
|
|
|
|
for i in 0..10 {
|
|
assert!(seen[i]);
|
|
}
|
|
# }
|
|
```
|
|
|
|
# Task ID guarantees
|
|
|
|
While a task is tracked in a `JoinSet`, that task's ID is unique relative
|
|
to all other running tasks in Tokio. For this purpose, tracking a task in a
|
|
`JoinSet` is equivalent to holding a [`JoinHandle`] to it. See the [task ID]
|
|
documentation for more info.
|
|
|
|
[`JoinHandle`]: crate::task::JoinHandle
|
|
[task ID]: crate::task::Id
|
|
|
|
```rust
|
|
pub struct JoinSet<T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn new() -> Self { /* ... */ }
|
|
```
|
|
Create a new `JoinSet`.
|
|
|
|
- ```rust
|
|
pub fn len(self: &Self) -> usize { /* ... */ }
|
|
```
|
|
Returns the number of tasks currently in the `JoinSet`.
|
|
|
|
- ```rust
|
|
pub fn is_empty(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns whether the `JoinSet` is empty.
|
|
|
|
- ```rust
|
|
pub fn build_task(self: &mut Self) -> Builder<''_, T> { /* ... */ }
|
|
```
|
|
Returns a [`Builder`] that can be used to configure a task prior to
|
|
|
|
- ```rust
|
|
pub fn spawn<F>(self: &mut Self, task: F) -> AbortHandle
|
|
where
|
|
F: Future<Output = T> + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the provided task on the `JoinSet`, returning an [`AbortHandle`]
|
|
|
|
- ```rust
|
|
pub fn spawn_on<F>(self: &mut Self, task: F, handle: &Handle) -> AbortHandle
|
|
where
|
|
F: Future<Output = T> + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the provided task on the provided runtime and store it in this
|
|
|
|
- ```rust
|
|
pub fn spawn_local<F>(self: &mut Self, task: F) -> AbortHandle
|
|
where
|
|
F: Future<Output = T> + ''static { /* ... */ }
|
|
```
|
|
Spawn the provided task on the current [`LocalSet`] or [`LocalRuntime`]
|
|
|
|
- ```rust
|
|
pub fn spawn_local_on<F>(self: &mut Self, task: F, local_set: &LocalSet) -> AbortHandle
|
|
where
|
|
F: Future<Output = T> + ''static { /* ... */ }
|
|
```
|
|
Spawn the provided task on the provided [`LocalSet`] and store it in
|
|
|
|
- ```rust
|
|
pub fn spawn_blocking<F>(self: &mut Self, f: F) -> AbortHandle
|
|
where
|
|
F: FnOnce() -> T + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the blocking code on the blocking threadpool and store
|
|
|
|
- ```rust
|
|
pub fn spawn_blocking_on<F>(self: &mut Self, f: F, handle: &Handle) -> AbortHandle
|
|
where
|
|
F: FnOnce() -> T + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the blocking code on the blocking threadpool of the
|
|
|
|
- ```rust
|
|
pub async fn join_next(self: &mut Self) -> Option<Result<T, JoinError>> { /* ... */ }
|
|
```
|
|
Waits until one of the tasks in the set completes and returns its output.
|
|
|
|
- ```rust
|
|
pub async fn join_next_with_id(self: &mut Self) -> Option<Result<(Id, T), JoinError>> { /* ... */ }
|
|
```
|
|
Waits until one of the tasks in the set completes and returns its
|
|
|
|
- ```rust
|
|
pub fn try_join_next(self: &mut Self) -> Option<Result<T, JoinError>> { /* ... */ }
|
|
```
|
|
Tries to join one of the tasks in the set that has completed and return its output.
|
|
|
|
- ```rust
|
|
pub fn try_join_next_with_id(self: &mut Self) -> Option<Result<(Id, T), JoinError>> { /* ... */ }
|
|
```
|
|
Tries to join one of the tasks in the set that has completed and return its output,
|
|
|
|
- ```rust
|
|
pub async fn shutdown(self: &mut Self) { /* ... */ }
|
|
```
|
|
Aborts all tasks and waits for them to finish shutting down.
|
|
|
|
- ```rust
|
|
pub async fn join_all(self: Self) -> Vec<T> { /* ... */ }
|
|
```
|
|
Awaits the completion of all tasks in this `JoinSet`, returning a vector of their results.
|
|
|
|
- ```rust
|
|
pub fn abort_all(self: &mut Self) { /* ... */ }
|
|
```
|
|
Aborts all tasks on this `JoinSet`.
|
|
|
|
- ```rust
|
|
pub fn detach_all(self: &mut Self) { /* ... */ }
|
|
```
|
|
Removes all tasks from this `JoinSet` without aborting them.
|
|
|
|
- ```rust
|
|
pub fn poll_join_next(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<Result<T, JoinError>>> { /* ... */ }
|
|
```
|
|
Polls for one of the tasks in the set to complete.
|
|
|
|
- ```rust
|
|
pub fn poll_join_next_with_id(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<Result<(Id, T), JoinError>>> { /* ... */ }
|
|
```
|
|
Polls for one of the tasks in the set to complete.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Default**
|
|
- ```rust
|
|
fn default() -> Self { /* ... */ }
|
|
```
|
|
|
|
- **Drop**
|
|
- ```rust
|
|
fn drop(self: &mut Self) { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **FromIterator**
|
|
- ```rust
|
|
fn from_iter<I: IntoIterator<Item = F>>(iter: I) -> Self { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Builder`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(tokio_unstable, feature = \"tracing\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(tokio_unstable, feature = \"tracing\"))))]")`
|
|
- `Other("#[doc(cfg(all(tokio_unstable, feature = \"tracing\")))]")`
|
|
- `MustUse { reason: Some("builders do nothing unless used to spawn a task") }`
|
|
|
|
A variant of [`task::Builder`] that spawns tasks on a [`JoinSet`] rather
|
|
than on the current default runtime.
|
|
|
|
[`task::Builder`]: crate::task::Builder
|
|
|
|
```rust
|
|
pub struct Builder<''a, T> {
|
|
// Some fields omitted
|
|
}
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Name | Type | Documentation |
|
|
|------|------|---------------|
|
|
| *private fields* | ... | *Some fields have been omitted* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn name(self: Self, name: &''a str) -> Self { /* ... */ }
|
|
```
|
|
Assigns a name to the task which will be spawned.
|
|
|
|
- ```rust
|
|
pub fn spawn<F>(self: Self, future: F) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: Future<Output = T> + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the provided task with this builder's settings and store it in the
|
|
|
|
- ```rust
|
|
pub fn spawn_on<F>(self: Self, future: F, handle: &Handle) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: Future<Output = T> + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the provided task on the provided [runtime handle] with this
|
|
|
|
- ```rust
|
|
pub fn spawn_blocking<F>(self: Self, f: F) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: FnOnce() -> T + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the blocking code on the blocking threadpool with this builder's
|
|
|
|
- ```rust
|
|
pub fn spawn_blocking_on<F>(self: Self, f: F, handle: &Handle) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: FnOnce() -> T + Send + ''static,
|
|
T: Send { /* ... */ }
|
|
```
|
|
Spawn the blocking code on the blocking threadpool of the provided
|
|
|
|
- ```rust
|
|
pub fn spawn_local<F>(self: Self, future: F) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: Future<Output = T> + ''static { /* ... */ }
|
|
```
|
|
Spawn the provided task on the current [`LocalSet`] with this builder's
|
|
|
|
- ```rust
|
|
pub fn spawn_local_on<F>(self: Self, future: F, local_set: &LocalSet) -> std::io::Result<AbortHandle>
|
|
where
|
|
F: Future<Output = T> + ''static { /* ... */ }
|
|
```
|
|
Spawn the provided task on the provided [`LocalSet`] with this builder's
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
## Module `futures`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
Task-related futures.
|
|
|
|
```rust
|
|
pub mod futures { /* ... */ }
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `TaskLocalFuture`
|
|
|
|
```rust
|
|
pub use super::task_local::TaskLocalFuture;
|
|
```
|
|
|
|
### Re-exports
|
|
|
|
#### Re-export `JoinError`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::JoinError;
|
|
```
|
|
|
|
#### Re-export `JoinHandle`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::JoinHandle;
|
|
```
|
|
|
|
#### Re-export `spawn_blocking`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use blocking::spawn_blocking;
|
|
```
|
|
|
|
#### Re-export `spawn`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use spawn::spawn;
|
|
```
|
|
|
|
#### Re-export `block_in_place`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt-multi-thread\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt-multi-thread\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt-multi-thread\"))]")`
|
|
|
|
```rust
|
|
pub use blocking::block_in_place;
|
|
```
|
|
|
|
#### Re-export `yield_now`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use yield_now::yield_now;
|
|
```
|
|
|
|
#### Re-export `spawn_local`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use local::spawn_local;
|
|
```
|
|
|
|
#### Re-export `LocalSet`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use local::LocalSet;
|
|
```
|
|
|
|
#### Re-export `LocalEnterGuard`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use local::LocalEnterGuard;
|
|
```
|
|
|
|
#### Re-export `LocalKey`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use task_local::LocalKey;
|
|
```
|
|
|
|
#### Re-export `JoinSet`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use join_set::JoinSet;
|
|
```
|
|
|
|
#### Re-export `AbortHandle`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::AbortHandle;
|
|
```
|
|
|
|
#### Re-export `Id`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::Id;
|
|
```
|
|
|
|
#### Re-export `id`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::id;
|
|
```
|
|
|
|
#### Re-export `try_id`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use crate::runtime::task::try_id;
|
|
```
|
|
|
|
#### Re-export `Builder`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(tokio_unstable, feature = \"tracing\"))]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(all(tokio_unstable, feature = \"tracing\"))))]")`
|
|
- `Other("#[doc(cfg(all(tokio_unstable, feature = \"tracing\")))]")`
|
|
|
|
```rust
|
|
pub use builder::Builder;
|
|
```
|
|
|
|
## Module `time`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"time\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"time\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"time\"))]")`
|
|
|
|
Utilities for tracking time.
|
|
|
|
This module provides a number of types for executing code after a set period
|
|
of time.
|
|
|
|
* [`Sleep`] is a future that does no work and completes at a specific [`Instant`]
|
|
in time.
|
|
|
|
* [`Interval`] is a stream yielding a value at a fixed period. It is
|
|
initialized with a [`Duration`] and repeatedly yields each time the duration
|
|
elapses.
|
|
|
|
* [`Timeout`]: Wraps a future or stream, setting an upper bound to the amount
|
|
of time it is allowed to execute. If the future or stream does not
|
|
complete in time, then it is canceled and an error is returned.
|
|
|
|
These types are sufficient for handling a large number of scenarios
|
|
involving time.
|
|
|
|
These types must be used from within the context of the [`Runtime`](crate::runtime::Runtime).
|
|
|
|
# Examples
|
|
|
|
Wait 100ms and print "100 ms have elapsed"
|
|
|
|
```
|
|
use std::time::Duration;
|
|
use tokio::time::sleep;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
sleep(Duration::from_millis(100)).await;
|
|
println!("100 ms have elapsed");
|
|
# }
|
|
```
|
|
|
|
Require that an operation takes no more than 1s.
|
|
|
|
```
|
|
use tokio::time::{timeout, Duration};
|
|
|
|
async fn long_future() {
|
|
// do work here
|
|
}
|
|
|
|
# async fn dox() {
|
|
let res = timeout(Duration::from_secs(1), long_future()).await;
|
|
|
|
if res.is_err() {
|
|
println!("operation timed out");
|
|
}
|
|
# }
|
|
```
|
|
|
|
A simple example using [`interval`] to execute a task every two seconds.
|
|
|
|
The difference between [`interval`] and [`sleep`] is that an [`interval`]
|
|
measures the time since the last tick, which means that `.tick().await` may
|
|
wait for a shorter time than the duration specified for the interval
|
|
if some time has passed between calls to `.tick().await`.
|
|
|
|
If the tick in the example below was replaced with [`sleep`], the task
|
|
would only be executed once every three seconds, and not every two
|
|
seconds.
|
|
|
|
```
|
|
use tokio::time;
|
|
|
|
async fn task_that_takes_a_second() {
|
|
println!("hello");
|
|
time::sleep(time::Duration::from_secs(1)).await
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut interval = time::interval(time::Duration::from_secs(2));
|
|
for _i in 0..5 {
|
|
interval.tick().await;
|
|
task_that_takes_a_second().await;
|
|
}
|
|
# }
|
|
```
|
|
|
|
[`interval`]: crate::time::interval()
|
|
[`sleep`]: sleep()
|
|
|
|
```rust
|
|
pub mod time { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `error`
|
|
|
|
Time error types.
|
|
|
|
```rust
|
|
pub mod error { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Struct `Error`
|
|
|
|
Errors encountered by the timer implementation.
|
|
|
|
Currently, there are two different errors that can occur:
|
|
|
|
* `shutdown` occurs when a timer operation is attempted, but the timer
|
|
instance has been dropped. In this case, the operation will never be able
|
|
to complete and the `shutdown` error is returned. This is a permanent
|
|
error, i.e., once this error is observed, timer operations will never
|
|
succeed in the future.
|
|
|
|
* `at_capacity` occurs when a timer operation is attempted, but the timer
|
|
instance is currently handling its maximum number of outstanding sleep instances.
|
|
In this case, the operation is not able to be performed at the current
|
|
moment, and `at_capacity` is returned. This is a transient error, i.e., at
|
|
some point in the future, if the operation is attempted again, it might
|
|
succeed. Callers that observe this error should attempt to [shed load]. One
|
|
way to do this would be dropping the future that issued the timer operation.
|
|
|
|
[shed load]: https://en.wikipedia.org/wiki/Load_Shedding
|
|
|
|
```rust
|
|
pub struct Error(/* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Methods
|
|
|
|
- ```rust
|
|
pub fn shutdown() -> Error { /* ... */ }
|
|
```
|
|
Creates an error representing a shutdown timer.
|
|
|
|
- ```rust
|
|
pub fn is_shutdown(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if the error was caused by the timer being shutdown.
|
|
|
|
- ```rust
|
|
pub fn at_capacity() -> Error { /* ... */ }
|
|
```
|
|
Creates an error representing a timer at capacity.
|
|
|
|
- ```rust
|
|
pub fn is_at_capacity(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if the error was caused by the timer being at capacity.
|
|
|
|
- ```rust
|
|
pub fn invalid() -> Error { /* ... */ }
|
|
```
|
|
Creates an error representing a misconfigured timer.
|
|
|
|
- ```rust
|
|
pub fn is_invalid(self: &Self) -> bool { /* ... */ }
|
|
```
|
|
Returns `true` if the error was caused by the timer being misconfigured.
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Clone**
|
|
- ```rust
|
|
fn clone(self: &Self) -> Error { /* ... */ }
|
|
```
|
|
|
|
- **CloneToUninit**
|
|
- ```rust
|
|
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
|
|
```
|
|
|
|
- **Copy**
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Sync**
|
|
- **ToOwned**
|
|
- ```rust
|
|
fn to_owned(self: &Self) -> T { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
|
|
```
|
|
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
#### Struct `Elapsed`
|
|
|
|
Errors returned by `Timeout`.
|
|
|
|
This error is returned when a timeout expires before the function was able
|
|
to finish.
|
|
|
|
```rust
|
|
pub struct Elapsed(/* private field */);
|
|
```
|
|
|
|
##### Fields
|
|
|
|
| Index | Type | Documentation |
|
|
|-------|------|---------------|
|
|
| 0 | `private` | *Private field* |
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Display**
|
|
- ```rust
|
|
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Eq**
|
|
- **Error**
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- ```rust
|
|
fn from(_err: Elapsed) -> std::io::Error { /* ... */ }
|
|
```
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **PartialEq**
|
|
- ```rust
|
|
fn eq(self: &Self, other: &Elapsed) -> bool { /* ... */ }
|
|
```
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **StructuralPartialEq**
|
|
- **Sync**
|
|
- **ToString**
|
|
- ```rust
|
|
fn to_string(self: &Self) -> String { /* ... */ }
|
|
```
|
|
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
### Re-exports
|
|
|
|
#### Re-export `advance`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"test-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"test-util\"))]")`
|
|
|
|
```rust
|
|
pub use clock::advance;
|
|
```
|
|
|
|
#### Re-export `pause`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"test-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"test-util\"))]")`
|
|
|
|
```rust
|
|
pub use clock::pause;
|
|
```
|
|
|
|
#### Re-export `resume`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"test-util\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"test-util\"))]")`
|
|
|
|
```rust
|
|
pub use clock::resume;
|
|
```
|
|
|
|
#### Re-export `Instant`
|
|
|
|
```rust
|
|
pub use self::instant::Instant;
|
|
```
|
|
|
|
#### Re-export `interval`
|
|
|
|
```rust
|
|
pub use interval::interval;
|
|
```
|
|
|
|
#### Re-export `interval_at`
|
|
|
|
```rust
|
|
pub use interval::interval_at;
|
|
```
|
|
|
|
#### Re-export `Interval`
|
|
|
|
```rust
|
|
pub use interval::Interval;
|
|
```
|
|
|
|
#### Re-export `MissedTickBehavior`
|
|
|
|
```rust
|
|
pub use interval::MissedTickBehavior;
|
|
```
|
|
|
|
#### Re-export `sleep`
|
|
|
|
```rust
|
|
pub use sleep::sleep;
|
|
```
|
|
|
|
#### Re-export `sleep_until`
|
|
|
|
```rust
|
|
pub use sleep::sleep_until;
|
|
```
|
|
|
|
#### Re-export `Sleep`
|
|
|
|
```rust
|
|
pub use sleep::Sleep;
|
|
```
|
|
|
|
#### Re-export `timeout`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use timeout::timeout;
|
|
```
|
|
|
|
#### Re-export `timeout_at`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use timeout::timeout_at;
|
|
```
|
|
|
|
#### Re-export `Timeout`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use timeout::Timeout;
|
|
```
|
|
|
|
#### Re-export `Duration`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[doc(no_inline)]")`
|
|
|
|
```rust
|
|
pub use std::time::Duration;
|
|
```
|
|
|
|
## Module `stream`
|
|
|
|
Due to the `Stream` trait's inclusion in `std` landing later than Tokio's 1.0
|
|
release, most of the Tokio stream utilities have been moved into the [`tokio-stream`]
|
|
crate.
|
|
|
|
# Why was `Stream` not included in Tokio 1.0?
|
|
|
|
Originally, we had planned to ship Tokio 1.0 with a stable `Stream` type
|
|
but unfortunately the [RFC] had not been merged in time for `Stream` to
|
|
reach `std` on a stable compiler in time for the 1.0 release of Tokio. For
|
|
this reason, the team has decided to move all `Stream` based utilities to
|
|
the [`tokio-stream`] crate. While this is not ideal, once `Stream` has made
|
|
it into the standard library and the `MSRV` period has passed, we will implement
|
|
stream for our different types.
|
|
|
|
While this may seem unfortunate, not all is lost as you can get much of the
|
|
`Stream` support with `async/await` and `while let` loops. It is also possible
|
|
to create a `impl Stream` from `async fn` using the [`async-stream`] crate.
|
|
|
|
[`tokio-stream`]: https://docs.rs/tokio-stream
|
|
[`async-stream`]: https://docs.rs/async-stream
|
|
[RFC]: https://github.com/rust-lang/rfcs/pull/2996
|
|
|
|
# Example
|
|
|
|
Convert a [`sync::mpsc::Receiver`] to an `impl Stream`.
|
|
|
|
```rust,no_run
|
|
use tokio::sync::mpsc;
|
|
|
|
let (tx, mut rx) = mpsc::channel::<usize>(16);
|
|
|
|
let stream = async_stream::stream! {
|
|
while let Some(item) = rx.recv().await {
|
|
yield item;
|
|
}
|
|
};
|
|
```
|
|
|
|
```rust
|
|
pub mod stream { /* ... */ }
|
|
```
|
|
|
|
## Module `doc`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(all(docsrs, unix))]")`
|
|
|
|
Types which are documented locally in the Tokio crate, but does not actually
|
|
live here.
|
|
|
|
**Note** this module is only visible on docs.rs, you cannot use it directly
|
|
in your own code.
|
|
|
|
```rust
|
|
pub mod doc { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `os`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(any(feature = \"net\", feature = \"fs\"))]")`
|
|
|
|
See [`std::os`](https://doc.rust-lang.org/std/os/index.html).
|
|
|
|
```rust
|
|
pub mod os { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `windows`
|
|
|
|
Platform-specific extensions to `std` for Windows.
|
|
|
|
See [`std::os::windows`](https://doc.rust-lang.org/std/os/windows/index.html).
|
|
|
|
```rust
|
|
pub mod windows { /* ... */ }
|
|
```
|
|
|
|
### Modules
|
|
|
|
## Module `io`
|
|
|
|
Windows-specific extensions to general I/O primitives.
|
|
|
|
See [`std::os::windows::io`](https://doc.rust-lang.org/std/os/windows/io/index.html).
|
|
|
|
```rust
|
|
pub mod io { /* ... */ }
|
|
```
|
|
|
|
### Types
|
|
|
|
#### Type Alias `RawHandle`
|
|
|
|
See [`std::os::windows::io::RawHandle`](https://doc.rust-lang.org/std/os/windows/io/type.RawHandle.html)
|
|
|
|
```rust
|
|
pub type RawHandle = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
#### Type Alias `OwnedHandle`
|
|
|
|
See [`std::os::windows::io::OwnedHandle`](https://doc.rust-lang.org/std/os/windows/io/struct.OwnedHandle.html)
|
|
|
|
```rust
|
|
pub type OwnedHandle = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
#### Type Alias `RawSocket`
|
|
|
|
See [`std::os::windows::io::RawSocket`](https://doc.rust-lang.org/std/os/windows/io/type.RawSocket.html)
|
|
|
|
```rust
|
|
pub type RawSocket = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
#### Type Alias `BorrowedHandle`
|
|
|
|
See [`std::os::windows::io::BorrowedHandle`](https://doc.rust-lang.org/std/os/windows/io/struct.BorrowedHandle.html)
|
|
|
|
```rust
|
|
pub type BorrowedHandle<''handle> = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
#### Type Alias `BorrowedSocket`
|
|
|
|
See [`std::os::windows::io::BorrowedSocket`](https://doc.rust-lang.org/std/os/windows/io/struct.BorrowedSocket.html)
|
|
|
|
```rust
|
|
pub type BorrowedSocket<''socket> = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
### Traits
|
|
|
|
#### Trait `AsRawHandle`
|
|
|
|
See [`std::os::windows::io::AsRawHandle`](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html)
|
|
|
|
```rust
|
|
pub trait AsRawHandle {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `as_raw_handle`: See [`std::os::windows::io::AsRawHandle::as_raw_handle`](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html#tymethod.as_raw_handle)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `File`
|
|
- `Stderr`
|
|
- `Stdin`
|
|
- `Stdout`
|
|
- `NamedPipeServer`
|
|
- `NamedPipeClient`
|
|
- `ChildStdin`
|
|
- `ChildStdout`
|
|
- `ChildStderr`
|
|
|
|
#### Trait `FromRawHandle`
|
|
|
|
See [`std::os::windows::io::FromRawHandle`](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawHandle.html)
|
|
|
|
```rust
|
|
pub trait FromRawHandle {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
> This trait is not object-safe and cannot be used in dynamic trait objects.
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `from_raw_handle`: See [`std::os::windows::io::FromRawHandle::from_raw_handle`](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawHandle.html#tymethod.from_raw_handle)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `File`
|
|
|
|
#### Trait `AsRawSocket`
|
|
|
|
See [`std::os::windows::io::AsRawSocket`](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawSocket.html)
|
|
|
|
```rust
|
|
pub trait AsRawSocket {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `as_raw_socket`: See [`std::os::windows::io::AsRawSocket::as_raw_socket`](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawSocket.html#tymethod.as_raw_socket)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `TcpListener`
|
|
- `TcpSocket`
|
|
- `TcpStream`
|
|
- `UdpSocket`
|
|
|
|
#### Trait `FromRawSocket`
|
|
|
|
See [`std::os::windows::io::FromRawSocket`](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawSocket.html)
|
|
|
|
```rust
|
|
pub trait FromRawSocket {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
> This trait is not object-safe and cannot be used in dynamic trait objects.
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `from_raw_socket`: See [`std::os::windows::io::FromRawSocket::from_raw_socket`](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawSocket.html#tymethod.from_raw_socket)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `TcpSocket`
|
|
|
|
#### Trait `IntoRawSocket`
|
|
|
|
See [`std::os::windows::io::IntoRawSocket`](https://doc.rust-lang.org/std/os/windows/io/trait.IntoRawSocket.html)
|
|
|
|
```rust
|
|
pub trait IntoRawSocket {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `into_raw_socket`: See [`std::os::windows::io::IntoRawSocket::into_raw_socket`](https://doc.rust-lang.org/std/os/windows/io/trait.IntoRawSocket.html#tymethod.into_raw_socket)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `TcpSocket`
|
|
|
|
#### Trait `AsHandle`
|
|
|
|
See [`std::os::windows::io::AsHandle`](https://doc.rust-lang.org/std/os/windows/io/trait.AsHandle.html)
|
|
|
|
```rust
|
|
pub trait AsHandle {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `as_handle`: See [`std::os::windows::io::AsHandle::as_handle`](https://doc.rust-lang.org/std/os/windows/io/trait.AsHandle.html#tymethod.as_handle)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `File`
|
|
- `Stderr`
|
|
- `Stdin`
|
|
- `Stdout`
|
|
- `NamedPipeServer`
|
|
- `NamedPipeClient`
|
|
- `ChildStdin`
|
|
- `ChildStdout`
|
|
- `ChildStderr`
|
|
|
|
#### Trait `AsSocket`
|
|
|
|
See [`std::os::windows::io::AsSocket`](https://doc.rust-lang.org/std/os/windows/io/trait.AsSocket.html)
|
|
|
|
```rust
|
|
pub trait AsSocket {
|
|
/* Associated items */
|
|
}
|
|
```
|
|
|
|
##### Required Items
|
|
|
|
###### Required Methods
|
|
|
|
- `as_socket`: See [`std::os::windows::io::AsSocket::as_socket`](https://doc.rust-lang.org/std/os/windows/io/trait.AsSocket.html#tymethod.as_socket)
|
|
|
|
##### Implementations
|
|
|
|
This trait is implemented for the following types:
|
|
|
|
- `TcpListener`
|
|
- `TcpSocket`
|
|
- `TcpStream`
|
|
- `UdpSocket`
|
|
|
|
### Types
|
|
|
|
#### Enum `NotDefinedHere`
|
|
|
|
The name of a type which is not defined here.
|
|
|
|
This is typically used as an alias for another type, like so:
|
|
|
|
```rust,ignore
|
|
/// See [some::other::location](https://example.com).
|
|
type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere;
|
|
```
|
|
|
|
This type is uninhabitable like the [`never` type] to ensure that no one
|
|
will ever accidentally use it.
|
|
|
|
[`never` type]: https://doc.rust-lang.org/std/primitive.never.html
|
|
|
|
```rust
|
|
pub enum NotDefinedHere {
|
|
}
|
|
```
|
|
|
|
##### Variants
|
|
|
|
##### Implementations
|
|
|
|
###### Trait Implementations
|
|
|
|
- **Any**
|
|
- ```rust
|
|
fn type_id(self: &Self) -> TypeId { /* ... */ }
|
|
```
|
|
|
|
- **Borrow**
|
|
- ```rust
|
|
fn borrow(self: &Self) -> &T { /* ... */ }
|
|
```
|
|
|
|
- **BorrowMut**
|
|
- ```rust
|
|
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
|
|
```
|
|
|
|
- **Debug**
|
|
- ```rust
|
|
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
|
|
```
|
|
|
|
- **Freeze**
|
|
- **From**
|
|
- ```rust
|
|
fn from(t: T) -> T { /* ... */ }
|
|
```
|
|
Returns the argument unchanged.
|
|
|
|
- **Instrument**
|
|
- **Into**
|
|
- ```rust
|
|
fn into(self: Self) -> U { /* ... */ }
|
|
```
|
|
Calls `U::from(self)`.
|
|
|
|
- **RefUnwindSafe**
|
|
- **Send**
|
|
- **Source**
|
|
- ```rust
|
|
fn register(self: &mut Self, _registry: &mio::Registry, _token: mio::Token, _interests: mio::Interest) -> std::io::Result<()> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn reregister(self: &mut Self, _registry: &mio::Registry, _token: mio::Token, _interests: mio::Interest) -> std::io::Result<()> { /* ... */ }
|
|
```
|
|
|
|
- ```rust
|
|
fn deregister(self: &mut Self, _registry: &mio::Registry) -> std::io::Result<()> { /* ... */ }
|
|
```
|
|
|
|
- **Sync**
|
|
- **TryFrom**
|
|
- ```rust
|
|
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **TryInto**
|
|
- ```rust
|
|
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
|
|
```
|
|
|
|
- **Unpin**
|
|
- **UnwindSafe**
|
|
- **WithSubscriber**
|
|
## Macros
|
|
|
|
### Macro `pin`
|
|
|
|
**Attributes:**
|
|
|
|
- `MacroExport`
|
|
|
|
Pins a value on the stack.
|
|
|
|
Calls to `async fn` return anonymous [`Future`] values that are `!Unpin`.
|
|
These values must be pinned before they can be polled. Calling `.await` will
|
|
handle this, but consumes the future. If it is required to call `.await` on
|
|
a `&mut _` reference, the caller is responsible for pinning the future.
|
|
|
|
Pinning may be done by allocating with [`Box::pin`] or by using the stack
|
|
with the `pin!` macro.
|
|
|
|
The following will **fail to compile**:
|
|
|
|
```compile_fail
|
|
async fn my_async_fn() {
|
|
// async logic here
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let mut future = my_async_fn();
|
|
(&mut future).await;
|
|
}
|
|
```
|
|
|
|
To make this work requires pinning:
|
|
|
|
```
|
|
use tokio::pin;
|
|
|
|
async fn my_async_fn() {
|
|
// async logic here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let future = my_async_fn();
|
|
pin!(future);
|
|
|
|
(&mut future).await;
|
|
# }
|
|
```
|
|
|
|
Pinning is useful when using `select!` and stream operators that require `T:
|
|
Stream + Unpin`.
|
|
|
|
[`Future`]: trait@std::future::Future
|
|
[`Box::pin`]: std::boxed::Box::pin
|
|
|
|
# Usage
|
|
|
|
The `pin!` macro takes **identifiers** as arguments. It does **not** work
|
|
with expressions.
|
|
|
|
The following does not compile as an expression is passed to `pin!`.
|
|
|
|
```compile_fail
|
|
async fn my_async_fn() {
|
|
// async logic here
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let mut future = pin!(my_async_fn());
|
|
(&mut future).await;
|
|
}
|
|
```
|
|
|
|
# Examples
|
|
|
|
Using with select:
|
|
|
|
```
|
|
use tokio::{pin, select};
|
|
use tokio_stream::{self as stream, StreamExt};
|
|
|
|
async fn my_async_fn() {
|
|
// async logic here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut stream = stream::iter(vec![1, 2, 3, 4]);
|
|
|
|
let future = my_async_fn();
|
|
pin!(future);
|
|
|
|
loop {
|
|
select! {
|
|
_ = &mut future => {
|
|
// Stop looping `future` will be polled after completion
|
|
break;
|
|
}
|
|
Some(val) = stream.next() => {
|
|
println!("got value = {}", val);
|
|
}
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
Because assigning to a variable followed by pinning is common, there is also
|
|
a variant of the macro that supports doing both in one go.
|
|
|
|
```
|
|
use tokio::{pin, select};
|
|
|
|
async fn my_async_fn() {
|
|
// async logic here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
pin! {
|
|
let future1 = my_async_fn();
|
|
let future2 = my_async_fn();
|
|
}
|
|
|
|
select! {
|
|
_ = &mut future1 => {}
|
|
_ = &mut future2 => {}
|
|
}
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub macro_rules! pin {
|
|
/* macro_rules! pin {
|
|
($($x:ident),*) => { ... };
|
|
($(
|
|
let $x:ident = $init:expr;
|
|
)*) => { ... };
|
|
} */
|
|
}
|
|
```
|
|
|
|
### Macro `select`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"macros\"))]")`
|
|
- `MacroExport`
|
|
|
|
Waits on multiple concurrent branches, returning when the **first** branch
|
|
completes, cancelling the remaining branches.
|
|
|
|
The `select!` macro must be used inside of async functions, closures, and
|
|
blocks.
|
|
|
|
The `select!` macro accepts one or more branches with the following pattern:
|
|
|
|
```text
|
|
<pattern> = <async expression> (, if <precondition>)? => <handler>,
|
|
```
|
|
|
|
Additionally, the `select!` macro may include a single, optional `else`
|
|
branch, which evaluates if none of the other branches match their patterns:
|
|
|
|
```text
|
|
else => <expression>
|
|
```
|
|
|
|
The macro aggregates all `<async expression>` expressions and runs them
|
|
concurrently on the **current** task. Once the **first** expression
|
|
completes with a value that matches its `<pattern>`, the `select!` macro
|
|
returns the result of evaluating the completed branch's `<handler>`
|
|
expression.
|
|
|
|
Additionally, each branch may include an optional `if` precondition. If the
|
|
precondition returns `false`, then the branch is disabled. The provided
|
|
`<async expression>` is still evaluated but the resulting future is never
|
|
polled. This capability is useful when using `select!` within a loop.
|
|
|
|
The complete lifecycle of a `select!` expression is as follows:
|
|
|
|
1. Evaluate all provided `<precondition>` expressions. If the precondition
|
|
returns `false`, disable the branch for the remainder of the current call
|
|
to `select!`. Re-entering `select!` due to a loop clears the "disabled"
|
|
state.
|
|
2. Aggregate the `<async expression>`s from each branch, including the
|
|
disabled ones. If the branch is disabled, `<async expression>` is still
|
|
evaluated, but the resulting future is not polled.
|
|
3. If **all** branches are disabled: go to step 6.
|
|
4. Concurrently await on the results for all remaining `<async expression>`s.
|
|
5. Once an `<async expression>` returns a value, attempt to apply the value to the
|
|
provided `<pattern>`. If the pattern matches, evaluate the `<handler>` and return.
|
|
If the pattern **does not** match, disable the current branch for the remainder of
|
|
the current call to `select!`. Continue from step 3.
|
|
6. Evaluate the `else` expression. If no else expression is provided, panic.
|
|
|
|
# Runtime characteristics
|
|
|
|
By running all async expressions on the current task, the expressions are
|
|
able to run **concurrently** but not in **parallel**. This means all
|
|
expressions are run on the same thread and if one branch blocks the thread,
|
|
all other expressions will be unable to continue. If parallelism is
|
|
required, spawn each async expression using [`tokio::spawn`] and pass the
|
|
join handle to `select!`.
|
|
|
|
[`tokio::spawn`]: crate::spawn
|
|
|
|
# Fairness
|
|
|
|
By default, `select!` randomly picks a branch to check first. This provides
|
|
some level of fairness when calling `select!` in a loop with branches that
|
|
are always ready.
|
|
|
|
This behavior can be overridden by adding `biased;` to the beginning of the
|
|
macro usage. See the examples for details. This will cause `select` to poll
|
|
the futures in the order they appear from top to bottom. There are a few
|
|
reasons you may want this:
|
|
|
|
- The random number generation of `tokio::select!` has a non-zero CPU cost
|
|
- Your futures may interact in a way where known polling order is significant
|
|
|
|
But there is an important caveat to this mode. It becomes your responsibility
|
|
to ensure that the polling order of your futures is fair. If for example you
|
|
are selecting between a stream and a shutdown future, and the stream has a
|
|
huge volume of messages and zero or nearly zero time between them, you should
|
|
place the shutdown future earlier in the `select!` list to ensure that it is
|
|
always polled, and will not be ignored due to the stream being constantly
|
|
ready.
|
|
|
|
# Panics
|
|
|
|
The `select!` macro panics if all branches are disabled **and** there is no
|
|
provided `else` branch. A branch is disabled when the provided `if`
|
|
precondition returns `false` **or** when the pattern does not match the
|
|
result of `<async expression>`.
|
|
|
|
# Cancellation safety
|
|
|
|
When using `select!` in a loop to receive messages from multiple sources,
|
|
you should make sure that the receive call is cancellation safe to avoid
|
|
losing messages. This section goes through various common methods and
|
|
describes whether they are cancel safe. The lists in this section are not
|
|
exhaustive.
|
|
|
|
The following methods are cancellation safe:
|
|
|
|
* [`tokio::sync::mpsc::Receiver::recv`](crate::sync::mpsc::Receiver::recv)
|
|
* [`tokio::sync::mpsc::UnboundedReceiver::recv`](crate::sync::mpsc::UnboundedReceiver::recv)
|
|
* [`tokio::sync::broadcast::Receiver::recv`](crate::sync::broadcast::Receiver::recv)
|
|
* [`tokio::sync::watch::Receiver::changed`](crate::sync::watch::Receiver::changed)
|
|
* [`tokio::net::TcpListener::accept`](crate::net::TcpListener::accept)
|
|
* [`tokio::net::UnixListener::accept`](crate::net::UnixListener::accept)
|
|
* [`tokio::signal::unix::Signal::recv`](crate::signal::unix::Signal::recv)
|
|
* [`tokio::io::AsyncReadExt::read`](crate::io::AsyncReadExt::read) on any `AsyncRead`
|
|
* [`tokio::io::AsyncReadExt::read_buf`](crate::io::AsyncReadExt::read_buf) on any `AsyncRead`
|
|
* [`tokio::io::AsyncWriteExt::write`](crate::io::AsyncWriteExt::write) on any `AsyncWrite`
|
|
* [`tokio::io::AsyncWriteExt::write_buf`](crate::io::AsyncWriteExt::write_buf) on any `AsyncWrite`
|
|
* [`tokio_stream::StreamExt::next`](https://docs.rs/tokio-stream/0.1/tokio_stream/trait.StreamExt.html#method.next) on any `Stream`
|
|
* [`futures::stream::StreamExt::next`](https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html#method.next) on any `Stream`
|
|
|
|
The following methods are not cancellation safe and can lead to loss of data:
|
|
|
|
* [`tokio::io::AsyncReadExt::read_exact`](crate::io::AsyncReadExt::read_exact)
|
|
* [`tokio::io::AsyncReadExt::read_to_end`](crate::io::AsyncReadExt::read_to_end)
|
|
* [`tokio::io::AsyncReadExt::read_to_string`](crate::io::AsyncReadExt::read_to_string)
|
|
* [`tokio::io::AsyncWriteExt::write_all`](crate::io::AsyncWriteExt::write_all)
|
|
|
|
The following methods are not cancellation safe because they use a queue for
|
|
fairness and cancellation makes you lose your place in the queue:
|
|
|
|
* [`tokio::sync::Mutex::lock`](crate::sync::Mutex::lock)
|
|
* [`tokio::sync::RwLock::read`](crate::sync::RwLock::read)
|
|
* [`tokio::sync::RwLock::write`](crate::sync::RwLock::write)
|
|
* [`tokio::sync::Semaphore::acquire`](crate::sync::Semaphore::acquire)
|
|
* [`tokio::sync::Notify::notified`](crate::sync::Notify::notified)
|
|
|
|
To determine whether your own methods are cancellation safe, look for the
|
|
location of uses of `.await`. This is because when an asynchronous method is
|
|
cancelled, that always happens at an `.await`. If your function behaves
|
|
correctly even if it is restarted while waiting at an `.await`, then it is
|
|
cancellation safe.
|
|
|
|
Cancellation safety can be defined in the following way: If you have a
|
|
future that has not yet completed, then it must be a no-op to drop that
|
|
future and recreate it. This definition is motivated by the situation where
|
|
a `select!` is used in a loop. Without this guarantee, you would lose your
|
|
progress when another branch completes and you restart the `select!` by
|
|
going around the loop.
|
|
|
|
Be aware that cancelling something that is not cancellation safe is not
|
|
necessarily wrong. For example, if you are cancelling a task because the
|
|
application is shutting down, then you probably don't care that partially
|
|
read data is lost.
|
|
|
|
# Examples
|
|
|
|
Basic select with two branches.
|
|
|
|
```
|
|
async fn do_stuff_async() {
|
|
// async work
|
|
}
|
|
|
|
async fn more_async_work() {
|
|
// more here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
tokio::select! {
|
|
_ = do_stuff_async() => {
|
|
println!("do_stuff_async() completed first")
|
|
}
|
|
_ = more_async_work() => {
|
|
println!("more_async_work() completed first")
|
|
}
|
|
};
|
|
# }
|
|
```
|
|
|
|
Basic stream selecting.
|
|
|
|
```
|
|
use tokio_stream::{self as stream, StreamExt};
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut stream1 = stream::iter(vec![1, 2, 3]);
|
|
let mut stream2 = stream::iter(vec![4, 5, 6]);
|
|
|
|
let next = tokio::select! {
|
|
v = stream1.next() => v.unwrap(),
|
|
v = stream2.next() => v.unwrap(),
|
|
};
|
|
|
|
assert!(next == 1 || next == 4);
|
|
# }
|
|
```
|
|
|
|
Collect the contents of two streams. In this example, we rely on pattern
|
|
matching and the fact that `stream::iter` is "fused", i.e. once the stream
|
|
is complete, all calls to `next()` return `None`.
|
|
|
|
```
|
|
use tokio_stream::{self as stream, StreamExt};
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut stream1 = stream::iter(vec![1, 2, 3]);
|
|
let mut stream2 = stream::iter(vec![4, 5, 6]);
|
|
|
|
let mut values = vec![];
|
|
|
|
loop {
|
|
tokio::select! {
|
|
Some(v) = stream1.next() => values.push(v),
|
|
Some(v) = stream2.next() => values.push(v),
|
|
else => break,
|
|
}
|
|
}
|
|
|
|
values.sort();
|
|
assert_eq!(&[1, 2, 3, 4, 5, 6], &values[..]);
|
|
# }
|
|
```
|
|
|
|
Using the same future in multiple `select!` expressions can be done by passing
|
|
a reference to the future. Doing so requires the future to be [`Unpin`]. A
|
|
future can be made [`Unpin`] by either using [`Box::pin`] or stack pinning.
|
|
|
|
[`Unpin`]: std::marker::Unpin
|
|
[`Box::pin`]: std::boxed::Box::pin
|
|
|
|
Here, a stream is consumed for at most 1 second.
|
|
|
|
```
|
|
use tokio_stream::{self as stream, StreamExt};
|
|
use tokio::time::{self, Duration};
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut stream = stream::iter(vec![1, 2, 3]);
|
|
let sleep = time::sleep(Duration::from_secs(1));
|
|
tokio::pin!(sleep);
|
|
|
|
loop {
|
|
tokio::select! {
|
|
maybe_v = stream.next() => {
|
|
if let Some(v) = maybe_v {
|
|
println!("got = {}", v);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
_ = &mut sleep => {
|
|
println!("timeout");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
Joining two values using `select!`.
|
|
|
|
```
|
|
use tokio::sync::oneshot;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (tx1, mut rx1) = oneshot::channel();
|
|
let (tx2, mut rx2) = oneshot::channel();
|
|
|
|
tokio::spawn(async move {
|
|
tx1.send("first").unwrap();
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
tx2.send("second").unwrap();
|
|
});
|
|
|
|
let mut a = None;
|
|
let mut b = None;
|
|
|
|
while a.is_none() || b.is_none() {
|
|
tokio::select! {
|
|
v1 = (&mut rx1), if a.is_none() => a = Some(v1.unwrap()),
|
|
v2 = (&mut rx2), if b.is_none() => b = Some(v2.unwrap()),
|
|
}
|
|
}
|
|
|
|
let res = (a.unwrap(), b.unwrap());
|
|
|
|
assert_eq!(res.0, "first");
|
|
assert_eq!(res.1, "second");
|
|
# }
|
|
```
|
|
|
|
Using the `biased;` mode to control polling order.
|
|
|
|
```
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let mut count = 0u8;
|
|
|
|
loop {
|
|
tokio::select! {
|
|
// If you run this example without `biased;`, the polling order is
|
|
// pseudo-random, and the assertions on the value of count will
|
|
// (probably) fail.
|
|
biased;
|
|
|
|
_ = async {}, if count < 1 => {
|
|
count += 1;
|
|
assert_eq!(count, 1);
|
|
}
|
|
_ = async {}, if count < 2 => {
|
|
count += 1;
|
|
assert_eq!(count, 2);
|
|
}
|
|
_ = async {}, if count < 3 => {
|
|
count += 1;
|
|
assert_eq!(count, 3);
|
|
}
|
|
_ = async {}, if count < 4 => {
|
|
count += 1;
|
|
assert_eq!(count, 4);
|
|
}
|
|
|
|
else => {
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
# }
|
|
```
|
|
|
|
## Avoid racy `if` preconditions
|
|
|
|
Given that `if` preconditions are used to disable `select!` branches, some
|
|
caution must be used to avoid missing values.
|
|
|
|
For example, here is **incorrect** usage of `sleep` with `if`. The objective
|
|
is to repeatedly run an asynchronous task for up to 50 milliseconds.
|
|
However, there is a potential for the `sleep` completion to be missed.
|
|
|
|
```no_run,should_panic
|
|
use tokio::time::{self, Duration};
|
|
|
|
async fn some_async_work() {
|
|
// do work
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let sleep = time::sleep(Duration::from_millis(50));
|
|
tokio::pin!(sleep);
|
|
|
|
while !sleep.is_elapsed() {
|
|
tokio::select! {
|
|
_ = &mut sleep, if !sleep.is_elapsed() => {
|
|
println!("operation timed out");
|
|
}
|
|
_ = some_async_work() => {
|
|
println!("operation completed");
|
|
}
|
|
}
|
|
}
|
|
|
|
panic!("This example shows how not to do it!");
|
|
# }
|
|
```
|
|
|
|
In the above example, `sleep.is_elapsed()` may return `true` even if
|
|
`sleep.poll()` never returned `Ready`. This opens up a potential race
|
|
condition where `sleep` expires between the `while !sleep.is_elapsed()`
|
|
check and the call to `select!` resulting in the `some_async_work()` call to
|
|
run uninterrupted despite the sleep having elapsed.
|
|
|
|
One way to write the above example without the race would be:
|
|
|
|
```
|
|
use tokio::time::{self, Duration};
|
|
|
|
async fn some_async_work() {
|
|
# time::sleep(Duration::from_millis(10)).await;
|
|
// do work
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let sleep = time::sleep(Duration::from_millis(50));
|
|
tokio::pin!(sleep);
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = &mut sleep => {
|
|
println!("operation timed out");
|
|
break;
|
|
}
|
|
_ = some_async_work() => {
|
|
println!("operation completed");
|
|
}
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
# Alternatives from the Ecosystem
|
|
|
|
The `select!` macro is a powerful tool for managing multiple asynchronous
|
|
branches, enabling tasks to run concurrently within the same thread. However,
|
|
its use can introduce challenges, particularly around cancellation safety, which
|
|
can lead to subtle and hard-to-debug errors. For many use cases, ecosystem
|
|
alternatives may be preferable as they mitigate these concerns by offering
|
|
clearer syntax, more predictable control flow, and reducing the need to manually
|
|
handle issues like fuse semantics or cancellation safety.
|
|
|
|
## Merging Streams
|
|
|
|
For cases where `loop { select! { ... } }` is used to poll multiple tasks,
|
|
stream merging offers a concise alternative, inherently handle cancellation-safe
|
|
processing, removing the risk of data loss. Libraries such as [`tokio_stream`],
|
|
[`futures::stream`] and [`futures_concurrency`] provide tools for merging
|
|
streams and handling their outputs sequentially.
|
|
|
|
[`tokio_stream`]: https://docs.rs/tokio-stream/latest/tokio_stream/
|
|
[`futures::stream`]: https://docs.rs/futures/latest/futures/stream/
|
|
[`futures_concurrency`]: https://docs.rs/futures-concurrency/latest/futures_concurrency/
|
|
|
|
### Example with `select!`
|
|
|
|
```
|
|
struct File;
|
|
struct Channel;
|
|
struct Socket;
|
|
|
|
impl Socket {
|
|
async fn read_packet(&mut self) -> Vec<u8> {
|
|
vec![]
|
|
}
|
|
}
|
|
|
|
async fn read_send(_file: &mut File, _channel: &mut Channel) {
|
|
// do work that is not cancel safe
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
// open our IO types
|
|
let mut file = File;
|
|
let mut channel = Channel;
|
|
let mut socket = Socket;
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = read_send(&mut file, &mut channel) => { /* ... */ },
|
|
_data = socket.read_packet() => { /* ... */ }
|
|
_ = futures::future::ready(()) => break
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
### Moving to `merge`
|
|
|
|
By using merge, you can unify multiple asynchronous tasks into a single stream,
|
|
eliminating the need to manage tasks manually and reducing the risk of
|
|
unintended behavior like data loss.
|
|
|
|
```
|
|
use std::pin::pin;
|
|
|
|
use futures::stream::unfold;
|
|
use tokio_stream::StreamExt;
|
|
|
|
struct File;
|
|
struct Channel;
|
|
struct Socket;
|
|
|
|
impl Socket {
|
|
async fn read_packet(&mut self) -> Vec<u8> {
|
|
vec![]
|
|
}
|
|
}
|
|
|
|
async fn read_send(_file: &mut File, _channel: &mut Channel) {
|
|
// do work that is not cancel safe
|
|
}
|
|
|
|
enum Message {
|
|
Stop,
|
|
Sent,
|
|
Data(Vec<u8>),
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
// open our IO types
|
|
let file = File;
|
|
let channel = Channel;
|
|
let socket = Socket;
|
|
|
|
let a = unfold((file, channel), |(mut file, mut channel)| async {
|
|
read_send(&mut file, &mut channel).await;
|
|
Some((Message::Sent, (file, channel)))
|
|
});
|
|
let b = unfold(socket, |mut socket| async {
|
|
let data = socket.read_packet().await;
|
|
Some((Message::Data(data), socket))
|
|
});
|
|
let c = tokio_stream::iter([Message::Stop]);
|
|
|
|
let mut s = pin!(a.merge(b).merge(c));
|
|
while let Some(msg) = s.next().await {
|
|
match msg {
|
|
Message::Data(_data) => { /* ... */ }
|
|
Message::Sent => continue,
|
|
Message::Stop => break,
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
## Racing Futures
|
|
|
|
If you need to wait for the first completion among several asynchronous tasks,
|
|
ecosystem utilities such as
|
|
[`futures`](https://docs.rs/futures/latest/futures/),
|
|
[`futures-lite`](https://docs.rs/futures-lite/latest/futures_lite/) or
|
|
[`futures-concurrency`](https://docs.rs/futures-concurrency/latest/futures_concurrency/)
|
|
provide streamlined syntax for racing futures:
|
|
|
|
- [`futures_concurrency::future::Race`](https://docs.rs/futures-concurrency/latest/futures_concurrency/future/trait.Race.html)
|
|
- [`futures::select`](https://docs.rs/futures/latest/futures/macro.select.html)
|
|
- [`futures::stream::select_all`](https://docs.rs/futures/latest/futures/stream/select_all/index.html) (for streams)
|
|
- [`futures_lite::future::or`](https://docs.rs/futures-lite/latest/futures_lite/future/fn.or.html)
|
|
- [`futures_lite::future::race`](https://docs.rs/futures-lite/latest/futures_lite/future/fn.race.html)
|
|
|
|
```
|
|
use futures_concurrency::future::Race;
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let task_a = async { Ok("ok") };
|
|
let task_b = async { Err("error") };
|
|
let result = (task_a, task_b).race().await;
|
|
|
|
match result {
|
|
Ok(output) => println!("First task completed with: {output}"),
|
|
Err(err) => eprintln!("Error occurred: {err}"),
|
|
}
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub macro_rules! select {
|
|
/* macro_rules! select {
|
|
{
|
|
$(
|
|
biased;
|
|
)?
|
|
$(
|
|
$bind:pat = $fut:expr $(, if $cond:expr)? => $handler:expr,
|
|
)*
|
|
$(
|
|
else => $els:expr $(,)?
|
|
)?
|
|
} => { ... };
|
|
} */
|
|
}
|
|
```
|
|
|
|
### Macro `join`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"macros\"))]")`
|
|
- `MacroExport`
|
|
|
|
Waits on multiple concurrent branches, returning when **all** branches
|
|
complete.
|
|
|
|
The `join!` macro must be used inside of async functions, closures, and
|
|
blocks.
|
|
|
|
The `join!` macro takes a list of async expressions and evaluates them
|
|
concurrently on the same task. Each async expression evaluates to a future
|
|
and the futures from each expression are multiplexed on the current task.
|
|
|
|
When working with async expressions returning `Result`, `join!` will wait
|
|
for **all** branches complete regardless if any complete with `Err`. Use
|
|
[`try_join!`] to return early when `Err` is encountered.
|
|
|
|
[`try_join!`]: crate::try_join
|
|
|
|
# Notes
|
|
|
|
The supplied futures are stored inline and do not require allocating a
|
|
`Vec`.
|
|
|
|
## Runtime characteristics
|
|
|
|
By running all async expressions on the current task, the expressions are
|
|
able to run **concurrently** but not in **parallel**. This means all
|
|
expressions are run on the same thread and if one branch blocks the thread,
|
|
all other expressions will be unable to continue. If parallelism is
|
|
required, spawn each async expression using [`tokio::spawn`] and pass the
|
|
join handle to `join!`.
|
|
|
|
[`tokio::spawn`]: crate::spawn
|
|
|
|
## Fairness
|
|
|
|
By default, `join!`'s generated future rotates which contained
|
|
future is polled first whenever it is woken.
|
|
|
|
This behavior can be overridden by adding `biased;` to the beginning of the
|
|
macro usage. See the examples for details. This will cause `join` to poll
|
|
the futures in the order they appear from top to bottom.
|
|
|
|
You may want this if your futures may interact in a way where known polling order is significant.
|
|
|
|
But there is an important caveat to this mode. It becomes your responsibility
|
|
to ensure that the polling order of your futures is fair. If for example you
|
|
are joining a stream and a shutdown future, and the stream has a
|
|
huge volume of messages that takes a long time to finish processing per poll, you should
|
|
place the shutdown future earlier in the `join!` list to ensure that it is
|
|
always polled, and will not be delayed due to the stream future taking a long time to return
|
|
`Poll::Pending`.
|
|
|
|
# Examples
|
|
|
|
Basic join with two branches
|
|
|
|
```
|
|
async fn do_stuff_async() {
|
|
// async work
|
|
}
|
|
|
|
async fn more_async_work() {
|
|
// more here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (first, second) = tokio::join!(
|
|
do_stuff_async(),
|
|
more_async_work());
|
|
|
|
// do something with the values
|
|
# }
|
|
```
|
|
|
|
Using the `biased;` mode to control polling order.
|
|
|
|
```
|
|
# #[cfg(not(target_family = "wasm"))]
|
|
# {
|
|
async fn do_stuff_async() {
|
|
// async work
|
|
}
|
|
|
|
async fn more_async_work() {
|
|
// more here
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let (first, second) = tokio::join!(
|
|
biased;
|
|
do_stuff_async(),
|
|
more_async_work()
|
|
);
|
|
|
|
// do something with the values
|
|
# }
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub macro_rules! join {
|
|
/* macro_rules! join {
|
|
($(biased;)? $($future:expr),*) => { ... };
|
|
} */
|
|
}
|
|
```
|
|
|
|
### Macro `try_join`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"macros\"))]")`
|
|
- `MacroExport`
|
|
|
|
Waits on multiple concurrent branches, returning when **all** branches
|
|
complete with `Ok(_)` or on the first `Err(_)`.
|
|
|
|
The `try_join!` macro must be used inside of async functions, closures, and
|
|
blocks.
|
|
|
|
Similar to [`join!`], the `try_join!` macro takes a list of async
|
|
expressions and evaluates them concurrently on the same task. Each async
|
|
expression evaluates to a future and the futures from each expression are
|
|
multiplexed on the current task. The `try_join!` macro returns when **all**
|
|
branches return with `Ok` or when the **first** branch returns with `Err`.
|
|
|
|
[`join!`]: macro@join
|
|
|
|
# Notes
|
|
|
|
The supplied futures are stored inline and do not require allocating a
|
|
`Vec`.
|
|
|
|
## Runtime characteristics
|
|
|
|
By running all async expressions on the current task, the expressions are
|
|
able to run **concurrently** but not in **parallel**. This means all
|
|
expressions are run on the same thread and if one branch blocks the thread,
|
|
all other expressions will be unable to continue. If parallelism is
|
|
required, spawn each async expression using [`tokio::spawn`] and pass the
|
|
join handle to `try_join!`.
|
|
|
|
[`tokio::spawn`]: crate::spawn
|
|
|
|
## Fairness
|
|
|
|
By default, `try_join!`'s generated future rotates which
|
|
contained future is polled first whenever it is woken.
|
|
|
|
This behavior can be overridden by adding `biased;` to the beginning of the
|
|
macro usage. See the examples for details. This will cause `try_join` to poll
|
|
the futures in the order they appear from top to bottom.
|
|
|
|
You may want this if your futures may interact in a way where known polling order is significant.
|
|
|
|
But there is an important caveat to this mode. It becomes your responsibility
|
|
to ensure that the polling order of your futures is fair. If for example you
|
|
are joining a stream and a shutdown future, and the stream has a
|
|
huge volume of messages that takes a long time to finish processing per poll, you should
|
|
place the shutdown future earlier in the `try_join!` list to ensure that it is
|
|
always polled, and will not be delayed due to the stream future taking a long time to return
|
|
`Poll::Pending`.
|
|
|
|
# Examples
|
|
|
|
Basic `try_join` with two branches.
|
|
|
|
```
|
|
async fn do_stuff_async() -> Result<(), &'static str> {
|
|
// async work
|
|
# Ok(())
|
|
}
|
|
|
|
async fn more_async_work() -> Result<(), &'static str> {
|
|
// more here
|
|
# Ok(())
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let res = tokio::try_join!(
|
|
do_stuff_async(),
|
|
more_async_work());
|
|
|
|
match res {
|
|
Ok((first, second)) => {
|
|
// do something with the values
|
|
}
|
|
Err(err) => {
|
|
println!("processing failed; error = {}", err);
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
Using `try_join!` with spawned tasks.
|
|
|
|
```
|
|
use tokio::task::JoinHandle;
|
|
|
|
async fn do_stuff_async() -> Result<(), &'static str> {
|
|
// async work
|
|
# Err("failed")
|
|
}
|
|
|
|
async fn more_async_work() -> Result<(), &'static str> {
|
|
// more here
|
|
# Ok(())
|
|
}
|
|
|
|
async fn flatten<T>(handle: JoinHandle<Result<T, &'static str>>) -> Result<T, &'static str> {
|
|
match handle.await {
|
|
Ok(Ok(result)) => Ok(result),
|
|
Ok(Err(err)) => Err(err),
|
|
Err(err) => Err("handling failed"),
|
|
}
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let handle1 = tokio::spawn(do_stuff_async());
|
|
let handle2 = tokio::spawn(more_async_work());
|
|
match tokio::try_join!(flatten(handle1), flatten(handle2)) {
|
|
Ok(val) => {
|
|
// do something with the values
|
|
}
|
|
Err(err) => {
|
|
println!("Failed with {}.", err);
|
|
# assert_eq!(err, "failed");
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
Using the `biased;` mode to control polling order.
|
|
|
|
```
|
|
async fn do_stuff_async() -> Result<(), &'static str> {
|
|
// async work
|
|
# Ok(())
|
|
}
|
|
|
|
async fn more_async_work() -> Result<(), &'static str> {
|
|
// more here
|
|
# Ok(())
|
|
}
|
|
|
|
# #[tokio::main(flavor = "current_thread")]
|
|
# async fn main() {
|
|
let res = tokio::try_join!(
|
|
biased;
|
|
do_stuff_async(),
|
|
more_async_work()
|
|
);
|
|
|
|
match res {
|
|
Ok((first, second)) => {
|
|
// do something with the values
|
|
}
|
|
Err(err) => {
|
|
println!("processing failed; error = {}", err);
|
|
}
|
|
}
|
|
# }
|
|
```
|
|
|
|
```rust
|
|
pub macro_rules! try_join {
|
|
/* macro_rules! try_join {
|
|
($(biased;)? $($future:expr),*) => { ... };
|
|
} */
|
|
}
|
|
```
|
|
|
|
### Macro `task_local`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `MacroExport`
|
|
|
|
Declares a new task-local key of type [`tokio::task::LocalKey`].
|
|
|
|
# Syntax
|
|
|
|
The macro wraps any number of static declarations and makes them local to the current task.
|
|
Publicity and attributes for each static is preserved. For example:
|
|
|
|
# Examples
|
|
|
|
```
|
|
# use tokio::task_local;
|
|
task_local! {
|
|
pub static ONE: u32;
|
|
|
|
#[allow(unused)]
|
|
static TWO: f32;
|
|
}
|
|
# fn main() {}
|
|
```
|
|
|
|
See [`LocalKey` documentation][`tokio::task::LocalKey`] for more
|
|
information.
|
|
|
|
[`tokio::task::LocalKey`]: struct@crate::task::LocalKey
|
|
|
|
```rust
|
|
pub macro_rules! task_local {
|
|
/* macro_rules! task_local {
|
|
() => { ... };
|
|
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty; $($rest:tt)*) => { ... };
|
|
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty) => { ... };
|
|
} */
|
|
}
|
|
```
|
|
|
|
## Re-exports
|
|
|
|
### Re-export `spawn`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
|
|
```rust
|
|
pub use task::spawn;
|
|
```
|
|
|
|
### Re-export `main`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[<cfg>(feature = \"rt-multi-thread\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"macros\"))]")`
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use tokio_macros::main;
|
|
```
|
|
|
|
### Re-export `test`
|
|
|
|
**Attributes:**
|
|
|
|
- `Other("#[<cfg>(feature = \"rt\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"rt\"))]")`
|
|
- `Other("#[<cfg>(feature = \"rt-multi-thread\")]")`
|
|
- `Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")`
|
|
- `Other("#[doc(cfg(feature = \"macros\"))]")`
|
|
- `Other("#[doc(inline)]")`
|
|
|
|
```rust
|
|
pub use tokio_macros::test;
|
|
```
|
|
|