Compare commits

...
Author SHA1 Message Date
Eliza Weisman 2a3c803dd1 chore: prepare Tokio v1.13.1 (#4235)
# 1.13.1 (November 15, 2021)

### Fixed

- sync: fix a data race between `oneshot::Sender::send` and awaiting a
  `oneshot::Receiver` when the oneshot has been closed ([#4226])

[#4226]: https://github.com/tokio-rs/tokio/pull/4226
2021-11-15 14:04:07 -08:00
Eliza Weisman 7d8de50482 oneshot: document UnsafeCell invariants (#4229)
Depends on #4226

## Motivation

Currently, the safety invariants and synchronization strategy used in
`tokio::sync::oneshot` are not particularly obvious, especially to a new
reader. It would be nice to better document this code to make these
invariants clearer.

## Solution

This branch adds `SAFETY:` comments to the `oneshot` channel
implementation. In particular, I've focused on documenting the
invariants around when the inner `UnsafeCell` that stores the value can
be accessed by the sender and receiver sides of the channel.

I still want to take a closer look at when the waker cells can be set,
and I'd like to add more documentation there in a follow-up branch.

Signed-off-by: Eliza Weisman <[email protected]>
2021-11-15 14:04:07 -08:00
Eliza Weisman ab0e60ddea sync: fix racy UnsafeCell access on a closed oneshot (#4226) 2021-11-15 14:04:07 -08:00
Alice Ryhl ac89d8926d chore: prepare Tokio v1.13.0 (#4196) 2021-10-29 18:34:13 +02:00
Alice Ryhl e184205421 chore: prepare tokio-macros 1.6.0 (#4197) 2021-10-29 18:33:40 +02:00
sander2 44a1aad8df task: allocate callback on heap immediately in debug mode (#4203) 2021-10-29 17:34:25 +02:00
Alice Ryhl 75c07770bf sync: make watch::send_replace infallible (#4195) 2021-10-27 14:05:25 +02:00
Colin Walters 268ed5e73e task: add more tips + links to spawn_blocking docs (#4150) 2021-10-26 20:57:57 +02:00
Bhargav 0c68b89452 codec: update stream impl for Framed to return None after Err (#4166) 2021-10-26 16:56:15 +02:00
Alice Ryhl 827694a9e3 ci: fix nightly version for cirrus ci (#4200) 2021-10-26 16:53:05 +02:00
Alice Ryhl d15e5fad16 ci: split FreeBSD into two jobs (#4194) 2021-10-26 15:44:00 +02:00
Alice Ryhl 9cb495cdb8 tokio: upgrade to new nightly for CI (#4193) 2021-10-26 14:08:11 +02:00
Ibraheem Ahmed e7d3e0c93c macros: use qualified syntax when polling in select! (#4192) 2021-10-25 23:54:34 +09:00
Alice Ryhl e04b5be1f5 time: update deadline on removal in DelayQueue (#4178) 2021-10-22 20:34:36 +02:00
Colin Walters 2734fa9a85 util/io: add SyncIoBridge (#4146) 2021-10-22 18:46:29 +02:00
Alice Ryhl 83aeae8610 chore: fix output of macro after new rustc release (#4189) 2021-10-22 09:36:12 +02:00
Taiki Endo cf550b2183 ci: ignore RUSTSEC-2020-0159 in audit (#4186) 2021-10-21 10:27:26 +02:00
Colin Walters e1c8b5a159 tests: add #[cfg(sync)] to watch test (#4183) 2021-10-21 09:11:14 +02:00
Jared Stanbrough eb7a615c96 tokio: add riscv32 to non atomic64 architectures (#4185) 2021-10-21 04:25:00 +09:00
John-John Tedro 44e9013f64 tokio: assert platform-minimum requirements at build time (#3797) 2021-10-19 15:16:45 +02:00
antogilbertandAntonello Palazzi 03969cdae7 doc: conversion of doc comments to indicative mood (#4174)
Co-authored-by: Antonello Palazzi <[email protected]>
2021-10-19 10:54:16 +02:00
Taiki Endo 095012b03b macros: fix type resolution error in #[tokio::main] (#4176) 2021-10-19 12:49:57 +09:00
Jonathan b5c1fb4012 signal: add example with background listener (#4171) 2021-10-17 20:37:15 +02:00
Philip Dubé d4848a9e2e examples: replace time crate with httpdate (#4169) 2021-10-15 15:21:08 +02:00
Alice Ryhl bb6a292d0a chore: prepare tokio-macros v1.5.0 (#4167) 2021-10-13 15:51:09 +02:00
Suika eb2106f87e runtime: reset woken of outer future after polled (#4157) 2021-10-12 13:35:14 +02:00
Lukas Wirth fadd0190da macros: make tokio-macros attributes more IDE friendly (#4162) 2021-10-11 22:04:47 +02:00
Alice Ryhl f0cb360d70 sync: add more oneshot examples (#4153) 2021-10-08 08:52:50 +02:00
Alice Ryhl d047584e86 time: document Interval::tick cancel safety (#4152) 2021-10-05 15:55:15 +02:00
Alice Ryhl c5d37204dc chore: fix unused field warnings (#4151) 2021-10-05 13:21:38 +02:00
我就像屎的倒影 7f26ad85c2 fmt: ignore the target dir when formatting (#4145)
Signed-off-by: hi-rustin <[email protected]>
2021-10-04 08:36:17 +02:00
Alice Ryhl d39c9ed9dc chore: prepare tokio-macros 1.4.1 (#4142)
This reverts commit 33f0a1fd2e.
2021-09-30 10:38:52 +02:00
Noah Kennedy 44cfe10ee5 chore: prepare tokio-macros 1.4.0 (#4139) 2021-09-29 23:30:47 +02:00
Frank Steffahn 1073f6e8be sync: expand Debug for Mutex<T> impl to unsized T (#4134) 2021-09-26 12:29:08 +02:00
Kai Jewson dee3236c97 sync: add watch::Sender::send_replace (#3962) 2021-09-25 22:06:40 +02:00
Noah Kennedy d9ca1517c6 net: add try_*, readable, writable, ready, and peer_addr methods to split halves (#4120) 2021-09-25 20:19:29 +02:00
你好-肚财 6c1a1d9b07 docs: add returning on the first error example for try_join! (#4133) 2021-09-25 16:04:38 +02:00
Arthur Gautier d32acd97eb net: add poll_{recv,send}_ready methods to udp and uds_datagram (#4131) 2021-09-24 20:28:18 +02:00
João Marcos Bezerra 7875f26586 docs: fixing broken links in tokio/src/lib.rs (#4132) 2021-09-24 11:16:30 +02:00
我就像屎的倒影 7ce8f05cff sync: add blocking_lock to Mutex (#4130) 2021-09-23 11:46:14 +02:00
Sean McArthur ea19606bc4 sync: fix Notify to clone the waker before locking its waiter list (#4129)
Since a waker can trigger arbitrary code, such as with a custom waker,
and even more so now that it can emit a tracing event that could do
respond, we must be careful about the internal state when that code is
triggered. The clone method of a waker is one of those instances.

This changes the internals of `Notify` so that the waker is cloned
*before* locking the waiter list. While this does mean that in some
contended cases, we'll have made an optimistic clone, it makes `Notify`
more robust and correct.

Note that the included test case is built from an instance that did
happen naturally in another project, see
https://github.com/tokio-rs/console/issues/133.
2021-09-23 08:33:14 +02:00
Zahari Dichev b9b59e4f15 tracing: use structured location fields for spawned tasks (#4128)
This change enables `tokio-console` to parse the location information
for a spawned task into a structured object rather than simply displaying
this info as a field on the task.

Signed-off-by: Zahari Dichev <[email protected]>
2021-09-22 23:17:41 +03:00
Suika cdc46a9ded io: add assert in copy_bidirectional that poll_write is sensible (#4125) 2021-09-22 10:06:51 +02:00
Zahari Dichev b9834f6d8b tracing: instrument time::Sleep (#4072)
This branch instruments the `Sleep` resource to allow the tokio-console
to consume data about resources usage. The corresponding console branch
is here: https://github.com/tokio-rs/console/pull/77

Signed-off-by: Zahari Dichev <[email protected]>
2021-09-22 08:34:41 +03:00
152 changed files with 2983 additions and 658 deletions
+7
View File
@@ -0,0 +1,7 @@
# See https://github.com/rustsec/rustsec/blob/59e1d2ad0b9cbc6892c26de233d4925074b4b97b/cargo-audit/audit.toml.example for example.
[advisories]
ignore = [
# https://github.com/tokio-rs/tokio/issues/4177
"RUSTSEC-2020-0159",
]
+34 -9
View File
@@ -1,15 +1,45 @@
freebsd_instance:
image: freebsd-12-2-release-amd64
env:
RUSTFLAGS: -D warnings
# Test FreeBSD in a full VM on cirrus-ci.com. Test the i686 target too, in the
# same VM. The binary will be built in 32-bit mode, but will execute on a
# 64-bit kernel and in a 64-bit environment. Our tests don't execute any of
# the system's binaries, so the environment shouldn't matter.
task:
name: FreeBSD
name: FreeBSD 64-bit
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain stable
- . $HOME/.cargo/env
- |
echo "~~~~ rustc --version ~~~~"
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo test --all --all-features
task:
name: FreeBSD docs
env:
LOOM_MAX_PREEMPTIONS: 2
RUSTFLAGS: -Dwarnings
RUSTFLAGS: --cfg docsrs
RUSTDOCFLAGS: --cfg docsrs -Dwarnings
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain nightly-2021-10-25
- . $HOME/.cargo/env
- |
echo "~~~~ rustc --version ~~~~"
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo doc --lib --no-deps --all-features --document-private-items
task:
name: FreeBSD 32-bit
setup_script:
- pkg install -y bash curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
@@ -21,9 +51,4 @@ task:
rustc --version
test_script:
- . $HOME/.cargo/env
- cargo test --all --all-features
- cargo doc --all --no-deps
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --all-features --target i686-unknown-freebsd
- cargo test --all --all-features --target i686-unknown-freebsd
+3 -3
View File
@@ -9,7 +9,7 @@ name: CI
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2021-07-09
nightly: nightly-2021-10-25
minrust: 1.45.2
jobs:
@@ -264,8 +264,8 @@ jobs:
- name: "rustfmt --check"
# Workaround for rust-lang/cargo#7732
run: |
if ! rustfmt --check --edition 2018 $(find . -name '*.rs' -print); then
printf "Please run \`rustfmt --edition 2018 \$(find . -name '*.rs' -print)\` to fix rustfmt errors.\nSee CONTRIBUTING.md for more details.\n" >&2
if ! rustfmt --check --edition 2018 $(git ls-files '*.rs'); then
printf "Please run \`rustfmt --edition 2018 \$(git ls-files '*.rs')\` to fix rustfmt errors.\nSee CONTRIBUTING.md for more details.\n" >&2
exit 1
fi
-1
View File
@@ -10,7 +10,6 @@ name: Loom
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2021-07-09
jobs:
loom:
+1 -1
View File
@@ -150,7 +150,7 @@ command below instead:
```
# Mac or Linux
rustfmt --check --edition 2018 $(find . -name '*.rs' -print)
rustfmt --check --edition 2018 $(git ls-files '*.rs')
# Powershell
Get-ChildItem . -Filter "*.rs" -Recurse | foreach { rustfmt --check --edition 2018 $_.FullName }
+1 -1
View File
@@ -56,7 +56,7 @@ Make sure you activated the full features of the tokio crate on Cargo.toml:
```toml
[dependencies]
tokio = { version = "1.12.0", features = ["full"] }
tokio = { version = "1.13.1", features = ["full"] }
```
Then, on your main.rs:
+1 -1
View File
@@ -20,7 +20,7 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
httparse = "1.0"
time = "0.1"
httpdate = "1.0"
once_cell = "1.5.2"
rand = "0.8.3"
+14 -10
View File
@@ -221,8 +221,9 @@ mod date {
use std::cell::RefCell;
use std::fmt::{self, Write};
use std::str;
use std::time::SystemTime;
use time::{self, Duration};
use httpdate::HttpDate;
pub struct Now(());
@@ -252,22 +253,26 @@ mod date {
struct LastRenderedNow {
bytes: [u8; 128],
amt: usize,
next_update: time::Timespec,
unix_date: u64,
}
thread_local!(static LAST: RefCell<LastRenderedNow> = RefCell::new(LastRenderedNow {
bytes: [0; 128],
amt: 0,
next_update: time::Timespec::new(0, 0),
unix_date: 0,
}));
impl fmt::Display for Now {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
LAST.with(|cache| {
let mut cache = cache.borrow_mut();
let now = time::get_time();
if now >= cache.next_update {
cache.update(now);
let now = SystemTime::now();
let now_unix = now
.duration_since(SystemTime::UNIX_EPOCH)
.map(|since_epoch| since_epoch.as_secs())
.unwrap_or(0);
if cache.unix_date != now_unix {
cache.update(now, now_unix);
}
f.write_str(cache.buffer())
})
@@ -279,11 +284,10 @@ mod date {
str::from_utf8(&self.bytes[..self.amt]).unwrap()
}
fn update(&mut self, now: time::Timespec) {
fn update(&mut self, now: SystemTime, now_unix: u64) {
self.amt = 0;
write!(LocalBuffer(self), "{}", time::at(now).rfc822()).unwrap();
self.next_update = now + Duration::seconds(1);
self.next_update.nsec = 0;
self.unix_date = now_unix;
write!(LocalBuffer(self), "{}", HttpDate::from(now)).unwrap();
}
}
@@ -12,6 +12,14 @@ async fn missing_return_type() {
#[tokio::main]
async fn extra_semicolon() -> Result<(), ()> {
/* TODO(taiki-e): help message still wrong
help: try using a variant of the expected enum
|
23 | Ok(Ok(());)
|
23 | Err(Ok(());)
|
*/
Ok(());
}
@@ -1,38 +1,45 @@
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:5:7
--> $DIR/macros_type_mismatch.rs:5:5
|
5 | Ok(())
| ^^^^ expected `()`, found enum `Result`
| ^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
help: consider using a semicolon here
|
5 | Ok(());
| ^
| +
help: try adding a return type
|
4 | async fn missing_semicolon_or_return_type() -> Result<(), _> {
| ^^^^^^^^^^^^^^^^
| ++++++++++++++++
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:10:18
--> $DIR/macros_type_mismatch.rs:10:5
|
9 | async fn missing_return_type() {
| - help: try adding a return type: `-> Result<(), _>`
10 | return Ok(());
| ^ expected `()`, found enum `Result`
| ^^^^^^^^^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<(), _>`
error[E0308]: mismatched types
--> $DIR/macros_type_mismatch.rs:14:31
--> $DIR/macros_type_mismatch.rs:23:5
|
14 | async fn extra_semicolon() -> Result<(), ()> {
| --------------- ^^^^^^^^^^^^^^ expected enum `Result`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
| -------------- expected `Result<(), ()>` because of return type
...
23 | Ok(());
| ^^^^^^^ expected enum `Result`, found `()`
|
= note: expected enum `Result<(), ()>`
found unit type `()`
help: try using a variant of the expected enum
|
23 | Ok(Ok(());)
|
23 | Err(Ok(());)
|
+33
View File
@@ -1,3 +1,36 @@
# 1.5.1 (October 29th, 2021)
- macros: fix type resolution error in `#[tokio::main]` ([#4176])
[#4176]: https://github.com/tokio-rs/tokio/pull/4176
# 1.5.0 (October 13th, 2021)
- macros: make tokio-macros attributes more IDE friendly ([#4162])
[#4162]: https://github.com/tokio-rs/tokio/pull/4162
# 1.4.1 (September 30th, 2021)
Reverted: run `current_thread` inside `LocalSet` ([#4027])
# 1.4.0 (September 29th, 2021)
(yanked)
### Changed
- macros: run `current_thread` inside `LocalSet` ([#4027])
- macros: explicitly relaxed clippy lint for `.expect()` in runtime entry macro ([#4030])
### Fixed
- macros: fix invalid error messages in functions wrapped with `#[main]` or `#[test]` ([#4067])
[#4027]: https://github.com/tokio-rs/tokio/pull/4027
[#4030]: https://github.com/tokio-rs/tokio/pull/4030
[#4067]: https://github.com/tokio-rs/tokio/pull/4067
# 1.3.0 (July 7, 2021)
- macros: don't trigger `clippy::unwrap_used` ([#3926])
+2 -2
View File
@@ -6,13 +6,13 @@ name = "tokio-macros"
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "tokio-macros-1.0.x" git tag.
version = "1.3.0"
version = "1.5.1"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-macros/1.3.0/tokio_macros"
documentation = "https://docs.rs/tokio-macros/1.5.1/tokio_macros"
description = """
Tokio's proc macros.
"""
+78 -38
View File
@@ -1,6 +1,10 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::Parser;
// syn::AttributeArgs does not implement syn::Parse
type AttributeArgs = syn::punctuated::Punctuated<syn::NestedMeta, syn::Token![,]>;
#[derive(Clone, Copy, PartialEq)]
enum RuntimeFlavor {
@@ -27,6 +31,13 @@ struct FinalConfig {
start_paused: Option<bool>,
}
/// Config used in case of the attribute not being able to build a valid config
const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig {
flavor: RuntimeFlavor::CurrentThread,
worker_threads: None,
start_paused: None,
};
struct Configuration {
rt_multi_thread_available: bool,
default_flavor: RuntimeFlavor,
@@ -184,13 +195,13 @@ fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result<bool, syn::Erro
}
}
fn parse_knobs(
mut input: syn::ItemFn,
args: syn::AttributeArgs,
fn build_config(
input: syn::ItemFn,
args: AttributeArgs,
is_test: bool,
rt_multi_thread: bool,
) -> Result<TokenStream, syn::Error> {
if input.sig.asyncness.take().is_none() {
) -> Result<FinalConfig, syn::Error> {
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return Err(syn::Error::new_spanned(input.sig.fn_token, msg));
}
@@ -278,7 +289,11 @@ fn parse_knobs(
}
}
let config = config.build()?;
config.build()
}
fn parse_knobs(mut input: syn::ItemFn, is_test: bool, config: FinalConfig) -> TokenStream {
input.sig.asyncness = None;
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, last_stmt_end_span) = {
@@ -324,25 +339,28 @@ fn parse_knobs(
let body = &input.block;
let brace_token = input.block.brace_token;
let (tail_return, tail_semicolon) = match body.stmts.last() {
Some(syn::Stmt::Semi(expr, _)) => (
match expr {
syn::Expr::Return(_) => quote! { return },
_ => quote! {},
Some(syn::Stmt::Semi(expr, _)) => match expr {
syn::Expr::Return(_) => (quote! { return }, quote! { ; }),
_ => match &input.sig.output {
syn::ReturnType::Type(_, ty) if matches!(&**ty, syn::Type::Tuple(ty) if ty.elems.is_empty()) =>
{
(quote! {}, quote! { ; }) // unit
}
syn::ReturnType::Default => (quote! {}, quote! { ; }), // unit
syn::ReturnType::Type(..) => (quote! {}, quote! {}), // ! or another
},
quote! {
;
},
),
},
_ => (quote! {}, quote! {}),
};
input.block = syn::parse2(quote_spanned! {last_stmt_end_span=>
{
let body = async #body;
#[allow(clippy::expect_used)]
#tail_return tokio::task::LocalSet::new().block_on(
&#rt.enable_all().build().expect("Failed building the Runtime"),
body,
)#tail_semicolon
#tail_return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body)#tail_semicolon
}
})
.expect("Parsing failure");
@@ -353,36 +371,58 @@ fn parse_knobs(
#input
};
Ok(result.into())
result.into()
}
fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
tokens.extend(TokenStream::from(error.into_compile_error()));
tokens
}
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
let config = if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
let msg = "the main function cannot accept arguments";
return syn::Error::new_spanned(&input.sig.ident, msg)
.to_compile_error()
.into();
}
Err(syn::Error::new_spanned(&input.sig.ident, msg))
} else {
AttributeArgs::parse_terminated
.parse(args)
.and_then(|args| build_config(input.clone(), args, false, rt_multi_thread))
};
parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
match config {
Ok(config) => parse_knobs(input, false, config),
Err(e) => token_stream_with_error(parse_knobs(input, false, DEFAULT_ERROR_CONFIG), e),
}
}
pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
let config = if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
Err(syn::Error::new_spanned(&attr, msg))
} else {
AttributeArgs::parse_terminated
.parse(args)
.and_then(|args| build_config(input.clone(), args, true, rt_multi_thread))
};
for attr in &input.attrs {
if attr.path.is_ident("test") {
let msg = "second test attribute is supplied";
return syn::Error::new_spanned(&attr, msg)
.to_compile_error()
.into();
}
match config {
Ok(config) => parse_knobs(input, true, config),
Err(e) => token_stream_with_error(parse_knobs(input, true, DEFAULT_ERROR_CONFIG), e),
}
parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}
+25 -33
View File
@@ -27,9 +27,6 @@ use proc_macro::TokenStream;
/// helps set up a `Runtime` without requiring the user to use
/// [Runtime](../tokio/runtime/struct.Runtime.html) or
/// [Builder](../tokio/runtime/struct.Builder.html) directly.
/// The function executes in the context of a
/// [LocalSet](../tokio/task/struct.LocalSet.html), allowing calls to
/// [spawn_local](../tokio/task/fn.spawn_local.html) without further setup.
///
/// Note: This macro is designed to be simplistic and targets applications that
/// do not require a complex setup. If the provided functionality is not
@@ -87,14 +84,13 @@ use proc_macro::TokenStream;
///
/// ```rust
/// fn main() {
/// let ls = tokio::task::LocalSet::new();
/// let rt = tokio::runtime::Builder::new_multi_thread()
/// tokio::runtime::Builder::new_multi_thread()
/// .enable_all()
/// .build()
/// .unwrap();
/// ls.block_on(&rt, async {
/// println!("Hello world");
/// })
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
@@ -113,14 +109,13 @@ use proc_macro::TokenStream;
///
/// ```rust
/// fn main() {
/// let ls = tokio::task::LocalSet::new();
/// let rt = tokio::runtime::Builder::new_current_thread()
/// tokio::runtime::Builder::new_current_thread()
/// .enable_all()
/// .build()
/// .unwrap();
/// ls.block_on(&rt, async {
/// println!("Hello world");
/// })
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
@@ -137,15 +132,14 @@ use proc_macro::TokenStream;
///
/// ```rust
/// fn main() {
/// let ls = tokio::task::LocalSet::new();
/// let rt = tokio::runtime::Builder::new_multi_thread()
/// tokio::runtime::Builder::new_multi_thread()
/// .worker_threads(2)
/// .enable_all()
/// .build()
/// .unwrap();
/// ls.block_on(&rt, async {
/// println!("Hello world");
/// })
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
@@ -162,15 +156,14 @@ use proc_macro::TokenStream;
///
/// ```rust
/// fn main() {
/// let ls = tokio::task::LocalSet::new();
/// let rt = tokio::runtime::Builder::new_current_thread()
/// tokio::runtime::Builder::new_current_thread()
/// .enable_all()
/// .start_paused(true)
/// .build()
/// .unwrap();
/// ls.block_on(&rt, async {
/// println!("Hello world");
/// })
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
@@ -211,14 +204,13 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
///
/// ```rust
/// fn main() {
/// let ls = tokio::task::LocalSet::new();
/// let rt = tokio::runtime::Builder::new_current_thread()
/// tokio::runtime::Builder::new_current_thread()
/// .enable_all()
/// .build()
/// .unwrap();
/// ls.block_on(&rt, async {
/// println!("Hello world");
/// })
/// .unwrap()
/// .block_on(async {
/// println!("Hello world");
/// })
/// }
/// ```
///
+2
View File
@@ -1,3 +1,5 @@
#![cfg(feature = "sync")]
use tokio::sync::watch;
use tokio_stream::wrappers::WatchStream;
use tokio_stream::StreamExt;
+2 -1
View File
@@ -23,13 +23,14 @@ categories = ["asynchronous"]
default = []
# Shorthand for enabling everything
full = ["codec", "compat", "io", "time", "net", "rt"]
full = ["codec", "compat", "io-util", "time", "net", "rt"]
net = ["tokio/net"]
compat = ["futures-io",]
codec = []
time = ["tokio/time","slab"]
io = []
io-util = ["io", "tokio/rt", "tokio/io-util"]
rt = ["tokio/rt"]
__docs_rs = ["futures-util"]
+12
View File
@@ -38,6 +38,18 @@ macro_rules! cfg_io {
}
}
cfg_io! {
macro_rules! cfg_io_util {
($($item:item)*) => {
$(
#[cfg(feature = "io-util")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
$item
)*
}
}
}
macro_rules! cfg_rt {
($($item:item)*) => {
$(
+1
View File
@@ -106,6 +106,7 @@ where
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(capacity),
has_errored: false,
},
write: WriteFrame::default(),
},
+56 -26
View File
@@ -27,10 +27,12 @@ pin_project! {
const INITIAL_CAPACITY: usize = 8 * 1024;
const BACKPRESSURE_BOUNDARY: usize = INITIAL_CAPACITY;
#[derive(Debug)]
pub(crate) struct ReadFrame {
pub(crate) eof: bool,
pub(crate) is_readable: bool,
pub(crate) buffer: BytesMut,
pub(crate) has_errored: bool,
}
pub(crate) struct WriteFrame {
@@ -49,6 +51,7 @@ impl Default for ReadFrame {
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(INITIAL_CAPACITY),
has_errored: false,
}
}
}
@@ -72,6 +75,7 @@ impl From<BytesMut> for ReadFrame {
buffer,
is_readable: size > 0,
eof: false,
has_errored: false,
}
}
}
@@ -126,30 +130,42 @@ where
//
// The initial state is `reading`.
//
// | state | eof | is_readable |
// |---------|-------|-------------|
// | reading | false | false |
// | framing | false | true |
// | pausing | true | true |
// | paused | true | false |
//
// `decode_eof`
// returns `Some` read 0 bytes
// │ │
//
// ┌───────┐ `decode_eof` ┌──────┐
// ┌──read 0 bytes──▶│pausing│─returns `None`─▶│paused│──┐
// │ └───────┘ └──────┘
// pending read┐────── │ ▲ │
// │ │ │ │ │
// │ ▼ │ `decode` returns `Some`│ pending read
// │ ╔═══════╗ ┌───────┐◀─┘
// └──║reading║─read n>0 bytes─▶│framing│
// ╚═══════╝ └───────┘◀──────read n>0 bytes┘
//
//
// └─`decode` returns `None`─
// | state | eof | is_readable | has_errored |
// |---------|-------|-------------|-------------|
// | reading | false | false | false |
// | framing | false | true | false |
// | pausing | true | true | false |
// | paused | true | false | false |
// | errored | <any> | <any> | true |
// `decode_eof` returns Err
// ┌────────────────────────────────────────────────────────┐
// `decode_eof` returns │
// `Ok(Some)` │
// ─────┐ `decode_eof` returns After returning │
// Read 0 bytes ├─────▼──┴┐ `Ok(None)` ┌────────┐ ◄───┐ `None` ┌───▼─────┐
// ┌────────────────►│ Pausing ├───────────────────────►│ Paused ├─┐ └───────────┤ Errored
// ─────────┘ └─┬──▲───┘ │ └───▲───▲─┘
// Pending read │ │ │ │
// ┌──────┐ │ `decode` returns `Some` │ └─────┘ │ │
// │ │ │ ┌────── │ Pending │
// │ ┌────▼──┴─┐ Read n>0 bytes ┌┴──────▼─┐ read n>0 bytes │ read
// └─┤ Reading ├───────────────►│ Framing │◄────────────────────────┘ │ │
// └──┬─▲────┘ └─────┬──┬┘ │
// │ │ │ │ `decode` returns Err │
// └───decode` returns `None`──┘ └───────────────────────────────────────────────────────┘ │
// │ read returns Err │
// └────────────────────────────────────────────────────────────────────────────────────────────┘
loop {
// Return `None` if we have encountered an error from the underlying decoder
// See: https://github.com/tokio-rs/tokio/issues/3976
if state.has_errored {
// preparing has_errored -> paused
trace!("Returning None and setting paused");
state.is_readable = false;
state.has_errored = false;
return Poll::Ready(None);
}
// Repeatedly call `decode` or `decode_eof` while the buffer is "readable",
// i.e. it _might_ contain data consumable as a frame or closing frame.
// Both signal that there is no such data by returning `None`.
@@ -165,7 +181,11 @@ where
// pausing or framing
if state.eof {
// pausing
let frame = pinned.codec.decode_eof(&mut state.buffer)?;
let frame = pinned.codec.decode_eof(&mut state.buffer).map_err(|err| {
trace!("Got an error, going to errored state");
state.has_errored = true;
err
})?;
if frame.is_none() {
state.is_readable = false; // prepare pausing -> paused
}
@@ -176,7 +196,11 @@ where
// framing
trace!("attempting to decode a frame");
if let Some(frame) = pinned.codec.decode(&mut state.buffer)? {
if let Some(frame) = pinned.codec.decode(&mut state.buffer).map_err(|op| {
trace!("Got an error, going to errored state");
state.has_errored = true;
op
})? {
trace!("frame decoded from buffer");
// implicit framing -> framing
return Poll::Ready(Some(Ok(frame)));
@@ -190,7 +214,13 @@ where
// Make sure we've got room for at least one byte to read to ensure
// that we don't get a spurious 0 that looks like EOF.
state.buffer.reserve(1);
let bytect = match poll_read_buf(pinned.inner.as_mut(), cx, &mut state.buffer)? {
let bytect = match poll_read_buf(pinned.inner.as_mut(), cx, &mut state.buffer).map_err(
|err| {
trace!("Got an error, going to errored state");
state.has_errored = true;
err
},
)? {
Poll::Ready(ct) => ct,
// implicit reading -> reading or implicit paused -> paused
Poll::Pending => return Poll::Pending,
+1
View File
@@ -51,6 +51,7 @@ where
eof: false,
is_readable: false,
buffer: BytesMut::with_capacity(capacity),
has_errored: false,
},
},
}
+9 -1
View File
@@ -1,14 +1,22 @@
//! Helpers for IO related tasks.
//!
//! These types are often used in combination with hyper or reqwest, as they
//! The stream types are often used in combination with hyper or reqwest, as they
//! allow converting between a hyper [`Body`] and [`AsyncRead`].
//!
//! The [`SyncIoBridge`] type converts from the world of async I/O
//! to synchronous I/O; this may often come up when using synchronous APIs
//! inside [`tokio::task::spawn_blocking`].
//!
//! [`Body`]: https://docs.rs/hyper/0.13/hyper/struct.Body.html
//! [`AsyncRead`]: tokio::io::AsyncRead
mod read_buf;
mod reader_stream;
mod stream_reader;
cfg_io_util! {
mod sync_bridge;
pub use self::sync_bridge::SyncIoBridge;
}
pub use self::read_buf::read_buf;
pub use self::reader_stream::ReaderStream;
+103
View File
@@ -0,0 +1,103 @@
use std::io::{Read, Write};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
/// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or
/// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`].
#[derive(Debug)]
pub struct SyncIoBridge<T> {
src: T,
rt: tokio::runtime::Handle,
}
impl<T: AsyncRead + Unpin> Read for SyncIoBridge<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let src = &mut self.src;
self.rt.block_on(AsyncReadExt::read(src, buf))
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
let src = &mut self.src;
self.rt.block_on(src.read_to_end(buf))
}
fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
let src = &mut self.src;
self.rt.block_on(src.read_to_string(buf))
}
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
let src = &mut self.src;
// The AsyncRead trait returns the count, synchronous doesn't.
let _n = self.rt.block_on(src.read_exact(buf))?;
Ok(())
}
}
impl<T: AsyncWrite + Unpin> Write for SyncIoBridge<T> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let src = &mut self.src;
self.rt.block_on(src.write(buf))
}
fn flush(&mut self) -> std::io::Result<()> {
let src = &mut self.src;
self.rt.block_on(src.flush())
}
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
let src = &mut self.src;
self.rt.block_on(src.write_all(buf))
}
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
let src = &mut self.src;
self.rt.block_on(src.write_vectored(bufs))
}
}
// Because https://doc.rust-lang.org/std/io/trait.Write.html#method.is_write_vectored is at the time
// of this writing still unstable, we expose this as part of a standalone method.
impl<T: AsyncWrite> SyncIoBridge<T> {
/// Determines if the underlying [`tokio::io::AsyncWrite`] target supports efficient vectored writes.
///
/// See [`tokio::io::AsyncWrite::is_write_vectored`].
pub fn is_write_vectored(&self) -> bool {
self.src.is_write_vectored()
}
}
impl<T: Unpin> SyncIoBridge<T> {
/// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or
/// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`].
///
/// When this struct is created, it captures a handle to the current thread's runtime with [`tokio::runtime::Handle::current`].
/// It is hence OK to move this struct into a separate thread outside the runtime, as created
/// by e.g. [`tokio::task::spawn_blocking`].
///
/// Stated even more strongly: to make use of this bridge, you *must* move
/// it into a separate thread outside the runtime. The synchronous I/O will use the
/// underlying handle to block on the backing asynchronous source, via
/// [`tokio::runtime::Handle::block_on`]. As noted in the documentation for that
/// function, an attempt to `block_on` from an asynchronous execution context
/// will panic.
///
/// # Wrapping `!Unpin` types
///
/// Use e.g. `SyncIoBridge::new(Box::pin(src))`.
///
/// # Panic
///
/// This will panic if called outside the context of a Tokio runtime.
pub fn new(src: T) -> Self {
Self::new_with_handle(src, tokio::runtime::Handle::current())
}
/// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or
/// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`].
///
/// This is the same as [`SyncIoBridge::new`], but allows passing an arbitrary handle and hence may
/// be initially invoked outside of an asynchronous context.
pub fn new_with_handle(src: T, rt: tokio::runtime::Handle) -> Self {
Self { src, rt }
}
}
+11
View File
@@ -498,9 +498,20 @@ impl<T> DelayQueue<T> {
/// # }
/// ```
pub fn remove(&mut self, key: &Key) -> Expired<T> {
let prev_deadline = self.next_deadline();
self.remove_key(key);
let data = self.slab.remove(key.index);
let next_deadline = self.next_deadline();
if prev_deadline != next_deadline {
match (next_deadline, &mut self.delay) {
(None, _) => self.delay = None,
(Some(deadline), Some(delay)) => delay.as_mut().reset(deadline),
(Some(deadline), None) => self.delay = Some(Box::pin(sleep_until(deadline))),
}
}
Expired {
key: Key::new(key.index),
data: data.inner,
+38
View File
@@ -0,0 +1,38 @@
use futures_core::stream::Stream;
use std::{io, pin::Pin};
use tokio_test::{assert_ready, io::Builder, task};
use tokio_util::codec::{BytesCodec, FramedRead};
macro_rules! pin {
($id:ident) => {
Pin::new(&mut $id)
};
}
macro_rules! assert_read {
($e:expr, $n:expr) => {{
let val = assert_ready!($e);
assert_eq!(val.unwrap().unwrap(), $n);
}};
}
#[tokio::test]
async fn return_none_after_error() {
let mut io = FramedRead::new(
Builder::new()
.read(b"abcdef")
.read_error(io::Error::new(io::ErrorKind::Other, "Resource errored out"))
.read(b"more data")
.build(),
BytesCodec::new(),
);
let mut task = task::spawn(());
task.enter(|cx, _| {
assert_read!(pin!(io).poll_next(cx), b"abcdef".to_vec());
assert!(assert_ready!(pin!(io).poll_next(cx)).unwrap().is_err());
assert!(assert_ready!(pin!(io).poll_next(cx)).is_none());
assert_read!(pin!(io).poll_next(cx), b"more data".to_vec());
})
}
+43
View File
@@ -0,0 +1,43 @@
#![cfg(feature = "io-util")]
use std::error::Error;
use std::io::{Cursor, Read, Result as IoResult};
use tokio::io::AsyncRead;
use tokio_util::io::SyncIoBridge;
async fn test_reader_len(
r: impl AsyncRead + Unpin + Send + 'static,
expected_len: usize,
) -> IoResult<()> {
let mut r = SyncIoBridge::new(r);
let res = tokio::task::spawn_blocking(move || {
let mut buf = Vec::new();
r.read_to_end(&mut buf)?;
Ok::<_, std::io::Error>(buf)
})
.await?;
assert_eq!(res?.len(), expected_len);
Ok(())
}
#[tokio::test]
async fn test_async_read_to_sync() -> Result<(), Box<dyn Error>> {
test_reader_len(tokio::io::empty(), 0).await?;
let buf = b"hello world";
test_reader_len(Cursor::new(buf), buf.len()).await?;
Ok(())
}
#[tokio::test]
async fn test_async_write_to_sync() -> Result<(), Box<dyn Error>> {
let mut dest = Vec::new();
let src = b"hello world";
let dest = tokio::task::spawn_blocking(move || -> Result<_, String> {
let mut w = SyncIoBridge::new(Cursor::new(&mut dest));
std::io::copy(&mut Cursor::new(src), &mut w).map_err(|e| e.to_string())?;
Ok(dest)
})
.await??;
assert_eq!(dest.as_slice(), src);
Ok(())
}
+10
View File
@@ -630,6 +630,16 @@ async fn insert_in_past_after_poll_fires_immediately() {
assert_eq!(entry, "bar");
}
#[tokio::test]
async fn delay_queue_poll_expired_when_empty() {
let mut delay_queue = task::spawn(DelayQueue::new());
let key = delay_queue.insert(0, std::time::Duration::from_secs(10));
assert_pending!(poll!(delay_queue));
delay_queue.remove(&key);
assert!(assert_ready!(poll!(delay_queue)).is_none());
}
fn ms(n: u64) -> Duration {
Duration::from_millis(n)
}
+65 -4
View File
@@ -1,3 +1,68 @@
# 1.13.1 (November 15, 2021)
### Fixed
- sync: fix a data race between `oneshot::Sender::send` and awaiting a
`oneshot::Receiver` when the oneshot has been closed ([#4226])
[#4226]: https://github.com/tokio-rs/tokio/pull/4226
# 1.13.0 (October 29, 2021)
### Fixed
- sync: fix `Notify` to clone the waker before locking its waiter list ([#4129])
- tokio: add riscv32 to non atomic64 architectures ([#4185])
### Added
- net: add `poll_{recv,send}_ready` methods to `udp` and `uds_datagram` ([#4131])
- net: add `try_*`, `readable`, `writable`, `ready`, and `peer_addr` methods to split halves ([#4120])
- sync: add `blocking_lock` to `Mutex` ([#4130])
- sync: add `watch::Sender::send_replace` ([#3962], [#4195])
- sync: expand `Debug` for `Mutex<T>` impl to unsized `T` ([#4134])
- tracing: instrument time::Sleep ([#4072])
- tracing: use structured location fields for spawned tasks ([#4128])
### Changed
- io: add assert in `copy_bidirectional` that `poll_write` is sensible ([#4125])
- macros: use qualified syntax when polling in `select!` ([#4192])
- runtime: handle `block_on` wakeups better ([#4157])
- task: allocate callback on heap immediately in debug mode ([#4203])
- tokio: assert platform-minimum requirements at build time ([#3797])
### Documented
- docs: conversion of doc comments to indicative mood ([#4174])
- docs: add returning on the first error example for `try_join!` ([#4133])
- docs: fixing broken links in `tokio/src/lib.rs` ([#4132])
- signal: add example with background listener ([#4171])
- sync: add more oneshot examples ([#4153])
- time: document `Interval::tick` cancel safety ([#4152])
[#3797]: https://github.com/tokio-rs/tokio/pull/3797
[#3962]: https://github.com/tokio-rs/tokio/pull/3962
[#4072]: https://github.com/tokio-rs/tokio/pull/4072
[#4120]: https://github.com/tokio-rs/tokio/pull/4120
[#4125]: https://github.com/tokio-rs/tokio/pull/4125
[#4128]: https://github.com/tokio-rs/tokio/pull/4128
[#4129]: https://github.com/tokio-rs/tokio/pull/4129
[#4130]: https://github.com/tokio-rs/tokio/pull/4130
[#4131]: https://github.com/tokio-rs/tokio/pull/4131
[#4132]: https://github.com/tokio-rs/tokio/pull/4132
[#4133]: https://github.com/tokio-rs/tokio/pull/4133
[#4134]: https://github.com/tokio-rs/tokio/pull/4134
[#4152]: https://github.com/tokio-rs/tokio/pull/4152
[#4153]: https://github.com/tokio-rs/tokio/pull/4153
[#4157]: https://github.com/tokio-rs/tokio/pull/4157
[#4171]: https://github.com/tokio-rs/tokio/pull/4171
[#4174]: https://github.com/tokio-rs/tokio/pull/4174
[#4185]: https://github.com/tokio-rs/tokio/pull/4185
[#4192]: https://github.com/tokio-rs/tokio/pull/4192
[#4195]: https://github.com/tokio-rs/tokio/pull/4195
[#4203]: https://github.com/tokio-rs/tokio/pull/4203
# 1.12.0 (September 21, 2021)
### Fixed
@@ -14,10 +79,6 @@
- runtime: callback when a worker parks and unparks ([#4070])
- sync: implement `try_recv` for mpsc channels ([#4113])
### Changed
- macros: run runtime inside `LocalSet` when using macro ([#4027])
### Documented
- docs: clarify CPU-bound tasks on Tokio ([#4105])
+2 -2
View File
@@ -7,12 +7,12 @@ name = "tokio"
# - README.md
# - Update CHANGELOG.md.
# - Create "v1.0.x" git tag.
version = "1.12.0"
version = "1.13.1"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
readme = "README.md"
documentation = "https://docs.rs/tokio/1.12.0/tokio/"
documentation = "https://docs.rs/tokio/1.13.1/tokio/"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
description = """
+1 -1
View File
@@ -56,7 +56,7 @@ Make sure you activated the full features of the tokio crate on Cargo.toml:
```toml
[dependencies]
tokio = { version = "1.12.0", features = ["full"] }
tokio = { version = "1.13.1", features = ["full"] }
```
Then, on your main.rs:
+5 -5
View File
@@ -69,14 +69,14 @@ cfg_rt_multi_thread! {
}
}
/// Run the given closure with a cooperative task budget. When the function
/// Runs the given closure with a cooperative task budget. When the function
/// returns, the budget is reset to the value prior to calling the function.
#[inline(always)]
pub(crate) fn budget<R>(f: impl FnOnce() -> R) -> R {
with_budget(Budget::initial(), f)
}
/// Run the given closure with an unconstrained task budget. When the function returns, the budget
/// Runs the given closure with an unconstrained task budget. When the function returns, the budget
/// is reset to the value prior to calling the function.
#[inline(always)]
pub(crate) fn with_unconstrained<R>(f: impl FnOnce() -> R) -> R {
@@ -108,7 +108,7 @@ fn with_budget<R>(budget: Budget, f: impl FnOnce() -> R) -> R {
}
cfg_rt_multi_thread! {
/// Set the current task's budget
/// Sets the current task's budget.
pub(crate) fn set(budget: Budget) {
CURRENT.with(|cell| cell.set(budget))
}
@@ -120,7 +120,7 @@ cfg_rt_multi_thread! {
}
cfg_rt! {
/// Forcibly remove the budgeting constraints early.
/// Forcibly removes the budgeting constraints early.
///
/// Returns the remaining budget
pub(crate) fn stop() -> Budget {
@@ -186,7 +186,7 @@ cfg_coop! {
}
impl Budget {
/// Decrement the budget. Returns `true` if successful. Decrementing fails
/// Decrements the budget. Returns `true` if successful. Decrementing fails
/// when there is not enough remaining budget.
fn decrement(&mut self) -> bool {
if let Some(num) = &mut self.0 {
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::fs::asyncify;
use std::io;
use std::path::Path;
/// Creates a new, empty directory at the provided path
/// Creates a new, empty directory at the provided path.
///
/// This is an async version of [`std::fs::create_dir`][std]
///
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct DirBuilder {
/// Indicates whether to create parent directories if they are missing.
recursive: bool,
/// Set the Unix mode for newly created directories.
/// Sets the Unix mode for newly created directories.
#[cfg(unix)]
pub(super) mode: Option<u32>,
}
+2 -2
View File
@@ -74,7 +74,7 @@ use std::fs::File as StdFile;
/// # }
/// ```
///
/// Read the contents of a file into a buffer
/// Read the contents of a file into a buffer:
///
/// ```no_run
/// use tokio::fs::File;
@@ -383,7 +383,7 @@ impl File {
asyncify(move || std.metadata()).await
}
/// Create a new `File` instance that shares the same underlying file handle
/// Creates a new `File` instance that shares the same underlying file handle
/// as the existing `File` instance. Reads, writes, and seeks will affect both
/// File instances simultaneously.
///
+1 -1
View File
@@ -430,7 +430,7 @@ feature! {
self
}
/// Pass custom flags to the `flags` argument of `open`.
/// Passes custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
+2 -2
View File
@@ -34,7 +34,7 @@ pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
Ok(ReadDir(State::Idle(Some(std))))
}
/// Read the the entries in a directory.
/// Reads the the entries in a directory.
///
/// This struct is returned from the [`read_dir`] function of this module and
/// will yield instances of [`DirEntry`]. Through a [`DirEntry`] information
@@ -287,7 +287,7 @@ impl DirEntry {
asyncify(move || std.file_type()).await
}
/// Returns a reference to the underlying `std::fs::DirEntry`
/// Returns a reference to the underlying `std::fs::DirEntry`.
#[cfg(unix)]
pub(super) fn as_inner(&self) -> &std::fs::DirEntry {
&self.0
+4 -4
View File
@@ -1,4 +1,4 @@
//! Definition of the MaybeDone combinator
//! Definition of the MaybeDone combinator.
use std::future::Future;
use std::mem;
@@ -8,9 +8,9 @@ use std::task::{Context, Poll};
/// A future that may have completed.
#[derive(Debug)]
pub enum MaybeDone<Fut: Future> {
/// A not-yet-completed future
/// A not-yet-completed future.
Future(Fut),
/// The output of the completed future
/// The output of the completed future.
Done(Fut::Output),
/// The empty variant after the result of a [`MaybeDone`] has been
/// taken using the [`take_output`](MaybeDone::take_output) method.
@@ -20,7 +20,7 @@ pub enum MaybeDone<Fut: Future> {
// Safe because we never generate `Pin<&mut Fut::Output>`
impl<Fut: Future + Unpin> Unpin for MaybeDone<Fut> {}
/// Wraps a future into a `MaybeDone`
/// Wraps a future into a `MaybeDone`.
pub fn maybe_done<Fut: Future>(future: Fut) -> MaybeDone<Fut> {
MaybeDone::Future(future)
}
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(dead_code)]
//! Definition of the `PollFn` adapter combinator
//! Definition of the `PollFn` adapter combinator.
use std::fmt;
use std::future::Future;
+2 -2
View File
@@ -205,13 +205,13 @@ impl<T: AsRawFd> AsyncFd<T> {
})
}
/// Returns a shared reference to the backing object of this [`AsyncFd`]
/// Returns a shared reference to the backing object of this [`AsyncFd`].
#[inline]
pub fn get_ref(&self) -> &T {
self.inner.as_ref().unwrap()
}
/// Returns a mutable reference to the backing object of this [`AsyncFd`]
/// Returns a mutable reference to the backing object of this [`AsyncFd`].
#[inline]
pub fn get_mut(&mut self) -> &mut T {
self.inner.as_mut().unwrap()
+2 -2
View File
@@ -16,7 +16,7 @@ use self::State::*;
pub(crate) struct Blocking<T> {
inner: Option<T>,
state: State<T>,
/// `true` if the lower IO layer needs flushing
/// `true` if the lower IO layer needs flushing.
need_flush: bool,
}
@@ -175,7 +175,7 @@ where
}
}
/// Repeats operations that are interrupted
/// Repeats operations that are interrupted.
macro_rules! uninterruptibly {
($e:expr) => {{
loop {
+4 -4
View File
@@ -1,4 +1,4 @@
//! Use POSIX AIO futures with Tokio
//! Use POSIX AIO futures with Tokio.
use crate::io::driver::{Handle, Interest, ReadyEvent, Registration};
use mio::event::Source;
@@ -16,14 +16,14 @@ use std::task::{Context, Poll};
/// Tokio's consumer must pass an implementor of this trait to create a
/// [`Aio`] object.
pub trait AioSource {
/// Register this AIO event source with Tokio's reactor
/// Registers this AIO event source with Tokio's reactor.
fn register(&mut self, kq: RawFd, token: usize);
/// Deregister this AIO event source with Tokio's reactor
/// Deregisters this AIO event source with Tokio's reactor.
fn deregister(&mut self);
}
/// Wrap the user's AioSource in order to implement mio::event::Source, which
/// Wraps the user's AioSource in order to implement mio::event::Source, which
/// is what the rest of the crate wants.
struct MioSource<T>(T);
+6 -6
View File
@@ -5,7 +5,7 @@ use crate::io::driver::Ready;
use std::fmt;
use std::ops;
/// Readiness event interest
/// Readiness event interest.
///
/// Specifies the readiness events the caller is interested in when awaiting on
/// I/O resource readiness states.
@@ -17,19 +17,19 @@ impl Interest {
// The non-FreeBSD definitions in this block are active only when
// building documentation.
cfg_aio! {
/// Interest for POSIX AIO
/// Interest for POSIX AIO.
#[cfg(target_os = "freebsd")]
pub const AIO: Interest = Interest(mio::Interest::AIO);
/// Interest for POSIX AIO
/// Interest for POSIX AIO.
#[cfg(not(target_os = "freebsd"))]
pub const AIO: Interest = Interest(mio::Interest::READABLE);
/// Interest for POSIX AIO lio_listio events
/// Interest for POSIX AIO lio_listio events.
#[cfg(target_os = "freebsd")]
pub const LIO: Interest = Interest(mio::Interest::LIO);
/// Interest for POSIX AIO lio_listio events
/// Interest for POSIX AIO lio_listio events.
#[cfg(not(target_os = "freebsd"))]
pub const LIO: Interest = Interest(mio::Interest::READABLE);
}
@@ -39,7 +39,7 @@ impl Interest {
/// Readable interest includes read-closed events.
pub const READABLE: Interest = Interest(mio::Interest::READABLE);
/// Interest in all writable events
/// Interest in all writable events.
///
/// Writable interest includes write-closed events.
pub const WRITABLE: Interest = Interest(mio::Interest::WRITABLE);
+9 -9
View File
@@ -23,10 +23,10 @@ use std::io;
use std::sync::{Arc, Weak};
use std::time::Duration;
/// I/O driver, backed by Mio
/// I/O driver, backed by Mio.
pub(crate) struct Driver {
/// Tracks the number of times `turn` is called. It is safe for this to wrap
/// as it is mostly used to determine when to call `compact()`
/// as it is mostly used to determine when to call `compact()`.
tick: u8,
/// Reuse the `mio::Events` value across calls to poll.
@@ -35,17 +35,17 @@ pub(crate) struct Driver {
/// Primary slab handle containing the state for each resource registered
/// with this driver. During Drop this is moved into the Inner structure, so
/// this is an Option to allow it to be vacated (until Drop this is always
/// Some)
/// Some).
resources: Option<Slab<ScheduledIo>>,
/// The system event queue
/// The system event queue.
poll: mio::Poll,
/// State shared between the reactor and the handles.
inner: Arc<Inner>,
}
/// A reference to an I/O driver
/// A reference to an I/O driver.
#[derive(Clone)]
pub(crate) struct Handle {
inner: Weak<Inner>,
@@ -66,13 +66,13 @@ pub(super) struct Inner {
/// without risking new ones being registered in the meantime.
resources: Mutex<Option<Slab<ScheduledIo>>>,
/// Registers I/O resources
/// Registers I/O resources.
registry: mio::Registry,
/// Allocates `ScheduledIo` handles when creating new resources.
pub(super) io_dispatch: slab::Allocator<ScheduledIo>,
/// Used to wake up the reactor from a call to `turn`
/// Used to wake up the reactor from a call to `turn`.
waker: mio::Waker,
}
@@ -253,7 +253,7 @@ impl fmt::Debug for Driver {
cfg_rt! {
impl Handle {
/// Returns a handle to the current reactor
/// Returns a handle to the current reactor.
///
/// # Panics
///
@@ -267,7 +267,7 @@ cfg_rt! {
cfg_not_rt! {
impl Handle {
/// Returns a handle to the current reactor
/// Returns a handle to the current reactor.
///
/// # Panics
///
+6 -6
View File
@@ -68,7 +68,7 @@ impl Ready {
ready
}
/// Returns true if `Ready` is the empty set
/// Returns true if `Ready` is the empty set.
///
/// # Examples
///
@@ -82,7 +82,7 @@ impl Ready {
self == Ready::EMPTY
}
/// Returns `true` if the value includes `readable`
/// Returns `true` if the value includes `readable`.
///
/// # Examples
///
@@ -98,7 +98,7 @@ impl Ready {
self.contains(Ready::READABLE) || self.is_read_closed()
}
/// Returns `true` if the value includes writable `readiness`
/// Returns `true` if the value includes writable `readiness`.
///
/// # Examples
///
@@ -114,7 +114,7 @@ impl Ready {
self.contains(Ready::WRITABLE) || self.is_write_closed()
}
/// Returns `true` if the value includes read-closed `readiness`
/// Returns `true` if the value includes read-closed `readiness`.
///
/// # Examples
///
@@ -129,7 +129,7 @@ impl Ready {
self.contains(Ready::READ_CLOSED)
}
/// Returns `true` if the value includes write-closed `readiness`
/// Returns `true` if the value includes write-closed `readiness`.
///
/// # Examples
///
@@ -154,7 +154,7 @@ impl Ready {
(self & other) == other
}
/// Create a `Ready` instance using the given `usize` representation.
/// Creates a `Ready` instance using the given `usize` representation.
///
/// The `usize` representation must have been obtained from a call to
/// `Readiness::as_usize`.
+10 -10
View File
@@ -36,16 +36,16 @@ cfg_io_readiness! {
#[derive(Debug, Default)]
struct Waiters {
#[cfg(feature = "net")]
/// List of all current waiters
/// List of all current waiters.
list: WaitList,
/// Waker used for AsyncRead
/// Waker used for AsyncRead.
reader: Option<Waker>,
/// Waker used for AsyncWrite
/// Waker used for AsyncWrite.
writer: Option<Waker>,
/// True if this ScheduledIo has been killed due to IO driver shutdown
/// True if this ScheduledIo has been killed due to IO driver shutdown.
is_shutdown: bool,
}
@@ -54,19 +54,19 @@ cfg_io_readiness! {
struct Waiter {
pointers: linked_list::Pointers<Waiter>,
/// The waker for this task
/// The waker for this task.
waker: Option<Waker>,
/// The interest this waiter is waiting on
/// The interest this waiter is waiting on.
interest: Interest,
is_ready: bool,
/// Should never be `!Unpin`
/// Should never be `!Unpin`.
_p: PhantomPinned,
}
/// Future returned by `readiness()`
/// Future returned by `readiness()`.
struct Readiness<'a> {
scheduled_io: &'a ScheduledIo,
@@ -276,7 +276,7 @@ impl ScheduledIo {
}
}
/// Poll version of checking readiness for a certain direction.
/// Polls for readiness events in a given direction.
///
/// These are to support `AsyncRead` and `AsyncWrite` polling methods,
/// which cannot use the `async fn` version. This uses reserved reader
@@ -363,7 +363,7 @@ unsafe impl Sync for ScheduledIo {}
cfg_io_readiness! {
impl ScheduledIo {
/// An async version of `poll_readiness` which uses a linked list of wakers
/// An async version of `poll_readiness` which uses a linked list of wakers.
pub(crate) async fn readiness(&self, interest: Interest) -> ReadyEvent {
self.readiness_fut(interest).await
}
+1 -1
View File
@@ -218,7 +218,7 @@ cfg_io_driver_impl! {
}
cfg_aio! {
/// BSD-specific I/O types
/// BSD-specific I/O types.
pub mod bsd {
mod poll_aio;
+2 -2
View File
@@ -113,7 +113,7 @@ impl<E: Source> PollEvented<E> {
})
}
/// Returns a reference to the registration
/// Returns a reference to the registration.
#[cfg(any(
feature = "net",
all(unix, feature = "process"),
@@ -123,7 +123,7 @@ impl<E: Source> PollEvented<E> {
&self.registration
}
/// Deregister the inner io from the registration and returns a Result containing the inner io
/// Deregisters the inner io from the registration and returns a Result containing the inner io.
#[cfg(any(feature = "net", feature = "process"))]
pub(crate) fn into_inner(mut self) -> io::Result<E> {
let mut inner = self.io.take().unwrap(); // As io shouldn't ever be None, just unwrap here.
+1 -1
View File
@@ -90,7 +90,7 @@ impl<T> ReadHalf<T> {
}
impl<T> WriteHalf<T> {
/// Check if this `WriteHalf` and some `ReadHalf` were split from the same
/// Checks if this `WriteHalf` and some `ReadHalf` were split from the same
/// stream.
pub fn is_pair_of(&self, other: &ReadHalf<T>) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
+1 -1
View File
@@ -7,7 +7,7 @@ use std::task::{Context, Poll};
/// if buffer contents seems to be utf8. Otherwise it only trims buffer down to MAX_BUF.
/// That's why, wrapped writer will always receive well-formed utf-8 bytes.
/// # Other platforms
/// passes data to `inner` as is
/// Passes data to `inner` as is.
#[derive(Debug)]
pub(crate) struct SplitByUtf8BoundaryIfWindows<W> {
inner: W,
+2 -2
View File
@@ -20,7 +20,7 @@ use std::io::IoSlice;
use bytes::Buf;
cfg_io_util! {
/// Defines numeric writer
/// Defines numeric writer.
macro_rules! write_impl {
(
$(
@@ -256,7 +256,7 @@ cfg_io_util! {
write_buf(self, src)
}
/// Attempts to write an entire buffer into this writer
/// Attempts to write an entire buffer into this writer.
///
/// Equivalent to:
///
+1 -1
View File
@@ -155,7 +155,7 @@ pub(super) enum SeekState {
Pending,
}
/// Seek to an offset, in bytes, in the underlying reader.
/// Seeks to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with `SeekFrom::Current(_)` is the
/// position the underlying reader would be at if the `BufReader` had no
+8
View File
@@ -84,6 +84,14 @@ impl CopyBuffer {
}
}
// If pos larger than cap, this loop will never stop.
// In particular, user's wrong poll_write implementation returning
// incorrect written length may lead to thread blocking.
debug_assert!(
self.pos <= self.cap,
"writer returned length larger than input slice"
);
// If we've written all the data and we've seen EOF, flush out the
// data and finish the transfer.
if self.pos == self.cap && self.read_done {
+3 -3
View File
@@ -8,7 +8,7 @@ use std::pin::Pin;
use std::task::{Context, Poll};
pin_project! {
/// Read lines from an [`AsyncBufRead`].
/// Reads lines from an [`AsyncBufRead`].
///
/// A `Lines` can be turned into a `Stream` with [`LinesStream`].
///
@@ -72,12 +72,12 @@ where
poll_fn(|cx| Pin::new(&mut *self).poll_next_line(cx)).await
}
/// Obtain a mutable reference to the underlying reader
/// Obtains a mutable reference to the underlying reader.
pub fn get_mut(&mut self) -> &mut R {
&mut self.reader
}
/// Obtain a reference to the underlying reader
/// Obtains a reference to the underlying reader.
pub fn get_ref(&mut self) -> &R {
&self.reader
}
+19 -2
View File
@@ -16,6 +16,10 @@
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg_hide))]
#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
#![cfg_attr(docsrs, doc(cfg_hide(loom)))]
#![cfg_attr(docsrs, doc(cfg_hide(not(loom))))]
#![cfg_attr(docsrs, allow(unused_attributes))]
//! A runtime for writing reliable network applications without compromising speed.
@@ -161,8 +165,8 @@
//! [`tokio::runtime`]: crate::runtime
//! [`Builder`]: crate::runtime::Builder
//! [`Runtime`]: crate::runtime::Runtime
//! [rt]: runtime/index.html#basic-scheduler
//! [rt-multi-thread]: runtime/index.html#threaded-scheduler
//! [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
@@ -350,6 +354,19 @@
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
// Test that pointer width is compatible. This asserts that e.g. usize is at
// least 32 bits, which a lot of components in Tokio currently assumes.
//
// TODO: improve once we have MSRV access to const eval to make more flexible.
#[cfg(not(any(
target_pointer_width = "32",
target_pointer_width = "64",
target_pointer_width = "128"
)))]
compile_error! {
"Tokio requires the platform pointer width to be 32, 64, or 128 bits"
}
// Includes re-exports used by macros.
//
// This module is not intended to be part of the public API. In general, any
+1 -1
View File
@@ -1,7 +1,7 @@
use std::sync::{self, MutexGuard, TryLockError};
/// Adapter for `std::Mutex` that removes the poisoning aspects
// from its api
/// from its api.
#[derive(Debug)]
pub(crate) struct Mutex<T: ?Sized>(sync::Mutex<T>);
+7 -4
View File
@@ -13,7 +13,7 @@ macro_rules! feature {
}
}
/// Enables enter::block_on
/// Enables enter::block_on.
macro_rules! cfg_block_on {
($($item:item)*) => {
$(
@@ -28,7 +28,7 @@ macro_rules! cfg_block_on {
}
}
/// Enables internal `AtomicWaker` impl
/// Enables internal `AtomicWaker` impl.
macro_rules! cfg_atomic_waker_impl {
($($item:item)*) => {
$(
@@ -99,6 +99,7 @@ macro_rules! cfg_io_driver_impl {
feature = "process",
all(unix, feature = "signal"),
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
$item
)*
}
@@ -422,7 +423,8 @@ macro_rules! cfg_has_atomic_u64 {
#[cfg(not(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc"
target_arch = "powerpc",
target_arch = "riscv32"
)))]
$item
)*
@@ -435,7 +437,8 @@ macro_rules! cfg_not_has_atomic_u64 {
#[cfg(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc"
target_arch = "powerpc",
target_arch = "riscv32"
))]
$item
)*
+1 -1
View File
@@ -1,4 +1,4 @@
/// Wait on multiple concurrent branches, returning when **all** branches
/// Waits on multiple concurrent branches, returning when **all** branches
/// complete.
///
/// The `join!` macro must be used inside of async functions, closures, and
+5
View File
@@ -15,6 +15,11 @@ mod ready;
#[macro_use]
mod thread_local;
cfg_trace! {
#[macro_use]
mod trace;
}
#[macro_use]
#[cfg(feature = "rt")]
pub(crate) mod scoped_tls;
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::loom::thread::LocalKey;
use std::cell::Cell;
use std::marker;
/// Set a reference as a thread-local
/// Sets a reference as a thread-local.
macro_rules! scoped_thread_local {
($(#[$attrs:meta])* $vis:vis static $name:ident: $ty:ty) => (
$(#[$attrs])*
+2 -2
View File
@@ -1,4 +1,4 @@
/// Wait on multiple concurrent branches, returning when the **first** branch
/// 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
@@ -502,7 +502,7 @@ macro_rules! select {
let mut fut = unsafe { Pin::new_unchecked(fut) };
// Try polling it
let out = match fut.poll(cx) {
let out = match Future::poll(fut, cx) {
Ready(out) => out,
Pending => {
// Track that at least one future is
+27
View File
@@ -0,0 +1,27 @@
cfg_trace! {
macro_rules! trace_op {
($name:literal, $readiness:literal, $parent:expr) => {
tracing::trace!(
target: "runtime::resource::poll_op",
parent: $parent,
op_name = $name,
is_ready = $readiness
);
}
}
macro_rules! trace_poll_op {
($name:literal, $poll:expr, $parent:expr $(,)*) => {
match $poll {
std::task::Poll::Ready(t) => {
trace_op!($name, true, $parent);
std::task::Poll::Ready(t)
}
std::task::Poll::Pending => {
trace_op!($name, false, $parent);
return std::task::Poll::Pending;
}
}
};
}
}
+40 -1
View File
@@ -1,4 +1,4 @@
/// Wait on multiple concurrent branches, returning when **all** branches
/// 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
@@ -59,6 +59,45 @@
/// }
/// }
/// ```
///
/// 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]
/// 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");
/// }
/// }
/// }
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
macro_rules! try_join {
+1 -1
View File
@@ -227,7 +227,7 @@ impl TcpListener {
Ok(TcpListener { io })
}
/// Turn a [`tokio::net::TcpListener`] into a [`std::net::TcpListener`].
/// Turns a [`tokio::net::TcpListener`] into a [`std::net::TcpListener`].
///
/// The returned [`std::net::TcpListener`] will have nonblocking mode set as
/// `true`. Use [`set_nonblocking`] to change the blocking mode if needed.
+1 -1
View File
@@ -1,4 +1,4 @@
//! TCP utility types
//! TCP utility types.
pub(crate) mod listener;
+10 -10
View File
@@ -87,7 +87,7 @@ cfg_net! {
}
impl TcpSocket {
/// Create a new socket configured for IPv4.
/// Creates a new socket configured for IPv4.
///
/// Calls `socket(2)` with `AF_INET` and `SOCK_STREAM`.
///
@@ -121,7 +121,7 @@ impl TcpSocket {
Ok(TcpSocket { inner })
}
/// Create a new socket configured for IPv6.
/// Creates a new socket configured for IPv6.
///
/// Calls `socket(2)` with `AF_INET6` and `SOCK_STREAM`.
///
@@ -155,7 +155,7 @@ impl TcpSocket {
Ok(TcpSocket { inner })
}
/// Allow the socket to bind to an in-use address.
/// Allows the socket to bind to an in-use address.
///
/// Behavior is platform specific. Refer to the target platform's
/// documentation for more details.
@@ -185,7 +185,7 @@ impl TcpSocket {
self.inner.set_reuseaddr(reuseaddr)
}
/// Retrieves the value set for `SO_REUSEADDR` on this socket
/// Retrieves the value set for `SO_REUSEADDR` on this socket.
///
/// # Examples
///
@@ -211,7 +211,7 @@ impl TcpSocket {
self.inner.get_reuseaddr()
}
/// Allow the socket to bind to an in-use port. Only available for unix systems
/// Allows the socket to bind to an in-use port. Only available for unix systems
/// (excluding Solaris & Illumos).
///
/// Behavior is platform specific. Refer to the target platform's
@@ -245,7 +245,7 @@ impl TcpSocket {
self.inner.set_reuseport(reuseport)
}
/// Allow the socket to bind to an in-use port. Only available for unix systems
/// Allows the socket to bind to an in-use port. Only available for unix systems
/// (excluding Solaris & Illumos).
///
/// Behavior is platform specific. Refer to the target platform's
@@ -348,7 +348,7 @@ impl TcpSocket {
self.inner.get_recv_buffer_size()
}
/// Get the local address of this socket.
/// Gets the local address of this socket.
///
/// Will fail on windows if called before `bind`.
///
@@ -374,7 +374,7 @@ impl TcpSocket {
self.inner.get_localaddr()
}
/// Bind the socket to the given address.
/// Binds the socket to the given address.
///
/// This calls the `bind(2)` operating-system function. Behavior is
/// platform specific. Refer to the target platform's documentation for more
@@ -406,7 +406,7 @@ impl TcpSocket {
self.inner.bind(addr)
}
/// Establish a TCP connection with a peer at the specified socket address.
/// Establishes a TCP connection with a peer at the specified socket address.
///
/// The `TcpSocket` is consumed. Once the connection is established, a
/// connected [`TcpStream`] is returned. If the connection fails, the
@@ -443,7 +443,7 @@ impl TcpSocket {
TcpStream::connect_mio(mio).await
}
/// Convert the socket into a `TcpListener`.
/// Converts the socket into a `TcpListener`.
///
/// `backlog` defines the maximum number of pending connections are queued
/// by the operating system at any given time. Connection are removed from
+212 -3
View File
@@ -9,14 +9,18 @@
//! level.
use crate::future::poll_fn;
use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::io::{AsyncRead, AsyncWrite, Interest, ReadBuf, Ready};
use crate::net::TcpStream;
use std::io;
use std::net::Shutdown;
use std::net::{Shutdown, SocketAddr};
use std::pin::Pin;
use std::task::{Context, Poll};
cfg_io_util! {
use bytes::BufMut;
}
/// Borrowed read half of a [`TcpStream`], created by [`split`].
///
/// Reading from a `ReadHalf` is usually done using the convenience methods found on the
@@ -49,7 +53,7 @@ pub(crate) fn split(stream: &mut TcpStream) -> (ReadHalf<'_>, WriteHalf<'_>) {
}
impl ReadHalf<'_> {
/// Attempt to receive data on the socket, without removing that data from
/// Attempts to receive data on the socket, without removing that data from
/// the queue, registering the current task for wakeup if data is not yet
/// available.
///
@@ -134,6 +138,211 @@ impl ReadHalf<'_> {
let mut buf = ReadBuf::new(buf);
poll_fn(|cx| self.poll_peek(cx, &mut buf)).await
}
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// This function is equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.0.ready(interest).await
}
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
///
/// This function is also equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn readable(&self) -> io::Result<()> {
self.0.readable().await
}
/// Tries to read data from the stream into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.try_read(buf)
}
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
/// written to possibly being only partially filled. This method behaves
/// equivalently to a single call to [`try_read()`] with concatenated
/// buffers.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_vectored()` is non-blocking, the buffer does not have to be
/// stored by the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`try_read()`]: Self::try_read()
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.try_read_vectored(bufs)
}
cfg_io_util! {
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
self.0.try_read_buf(buf)
}
}
/// Returns the remote address that this stream is connected to.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
/// Returns the local address that this stream is bound to.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
}
impl WriteHalf<'_> {
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// This function is equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.0.ready(interest).await
}
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn writable(&self) -> io::Result<()> {
self.0.writable().await
}
/// Tries to write a buffer to the stream, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
/// only part of the buffer may be written.
///
/// This function is usually paired with `writable()`.
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.try_write(buf)
}
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
/// from possible being only partially consumed. This method behaves
/// equivalently to a single call to [`try_write()`] with concatenated
/// buffers.
///
/// This function is usually paired with `writable()`.
///
/// [`try_write()`]: Self::try_write()
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.try_write_vectored(bufs)
}
/// Returns the remote address that this stream is connected to.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
/// Returns the local address that this stream is bound to.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
}
impl AsyncRead for ReadHalf<'_> {
+210 -3
View File
@@ -9,16 +9,20 @@
//! level.
use crate::future::poll_fn;
use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::io::{AsyncRead, AsyncWrite, Interest, ReadBuf, Ready};
use crate::net::TcpStream;
use std::error::Error;
use std::net::Shutdown;
use std::net::{Shutdown, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::{fmt, io};
cfg_io_util! {
use bytes::BufMut;
}
/// Owned read half of a [`TcpStream`], created by [`into_split`].
///
/// Reading from an `OwnedReadHalf` is usually done using the convenience methods found
@@ -189,6 +193,128 @@ impl OwnedReadHalf {
let mut buf = ReadBuf::new(buf);
poll_fn(|cx| self.poll_peek(cx, &mut buf)).await
}
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// This function is equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.inner.ready(interest).await
}
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
///
/// This function is also equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn readable(&self) -> io::Result<()> {
self.inner.readable().await
}
/// Tries to read data from the stream into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.try_read(buf)
}
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
/// written to possibly being only partially filled. This method behaves
/// equivalently to a single call to [`try_read()`] with concatenated
/// buffers.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_vectored()` is non-blocking, the buffer does not have to be
/// stored by the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`try_read()`]: Self::try_read()
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.try_read_vectored(bufs)
}
cfg_io_util! {
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
self.inner.try_read_buf(buf)
}
}
/// Returns the remote address that this stream is connected to.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
}
/// Returns the local address that this stream is bound to.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
}
impl AsyncRead for OwnedReadHalf {
@@ -211,13 +337,94 @@ impl OwnedWriteHalf {
reunite(other, self)
}
/// Destroy the write half, but don't close the write half of the stream
/// Destroys the write half, but don't close the write half of the stream
/// until the read half is dropped. If the read half has already been
/// dropped, this closes the stream.
pub fn forget(mut self) {
self.shutdown_on_drop = false;
drop(self);
}
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// This function is equivalent to [`TcpStream::ready`].
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.inner.ready(interest).await
}
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn writable(&self) -> io::Result<()> {
self.inner.writable().await
}
/// Tries to write a buffer to the stream, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
/// only part of the buffer may be written.
///
/// This function is usually paired with `writable()`.
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write(&self, buf: &[u8]) -> io::Result<usize> {
self.inner.try_write(buf)
}
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
/// from possible being only partially consumed. This method behaves
/// equivalently to a single call to [`try_write()`] with concatenated
/// buffers.
///
/// This function is usually paired with `writable()`.
///
/// [`try_write()`]: Self::try_write()
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.inner.try_write_vectored(bufs)
}
/// Returns the remote address that this stream is connected to.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
}
/// Returns the local address that this stream is bound to.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
}
impl Drop for OwnedWriteHalf {
+9 -9
View File
@@ -192,7 +192,7 @@ impl TcpStream {
Ok(TcpStream { io })
}
/// Turn a [`tokio::net::TcpStream`] into a [`std::net::TcpStream`].
/// Turns a [`tokio::net::TcpStream`] into a [`std::net::TcpStream`].
///
/// The returned [`std::net::TcpStream`] will have nonblocking mode set as `true`.
/// Use [`set_nonblocking`] to change the blocking mode if needed.
@@ -350,7 +350,7 @@ impl TcpStream {
}
}
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
@@ -422,7 +422,7 @@ impl TcpStream {
Ok(event.ready)
}
/// Wait for the socket to become readable.
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
@@ -510,7 +510,7 @@ impl TcpStream {
self.io.registration().poll_read_ready(cx).map_ok(|_| ())
}
/// Try to read data from the stream into the provided buffer, returning how
/// Tries to read data from the stream into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
@@ -577,7 +577,7 @@ impl TcpStream {
.try_io(Interest::READABLE, || (&*self.io).read(buf))
}
/// Try to read data from the stream into the provided buffers, returning
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
@@ -656,7 +656,7 @@ impl TcpStream {
}
cfg_io_util! {
/// Try to read data from the stream into the provided buffer, advancing the
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
@@ -734,7 +734,7 @@ impl TcpStream {
}
}
/// Wait for the socket to become writable.
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
@@ -874,7 +874,7 @@ impl TcpStream {
.try_io(Interest::WRITABLE, || (&*self.io).write(buf))
}
/// Try to write several buffers to the stream, returning how many bytes
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
@@ -936,7 +936,7 @@ impl TcpStream {
.try_io(Interest::WRITABLE, || (&*self.io).write_vectored(bufs))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
+78 -12
View File
@@ -12,7 +12,7 @@ cfg_io_util! {
}
cfg_net! {
/// A UDP socket
/// A UDP socket.
///
/// UDP is "connectionless", unlike TCP. Meaning, regardless of what address you've bound to, a `UdpSocket`
/// is free to communicate with many different remotes. In tokio there are basically two main ways to use `UdpSocket`:
@@ -211,7 +211,7 @@ impl UdpSocket {
UdpSocket::new(io)
}
/// Turn a [`tokio::net::UdpSocket`] into a [`std::net::UdpSocket`].
/// Turns a [`tokio::net::UdpSocket`] into a [`std::net::UdpSocket`].
///
/// The returned [`std::net::UdpSocket`] will have nonblocking mode set as
/// `true`. Use [`set_nonblocking`] to change the blocking mode if needed.
@@ -317,7 +317,7 @@ impl UdpSocket {
}))
}
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_recv()` or `try_send()`. It
/// can be used to concurrently recv / send to the same socket on a single
@@ -388,7 +388,7 @@ impl UdpSocket {
Ok(event.ready)
}
/// Wait for the socket to become writable.
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is
/// usually paired with `try_send()` or `try_send_to()`.
@@ -443,6 +443,39 @@ impl UdpSocket {
Ok(())
}
/// Polls for write/send readiness.
///
/// If the udp stream is not currently ready for sending, this method will
/// store a clone of the `Waker` from the provided `Context`. When the udp
/// stream becomes ready for sending, `Waker::wake` will be called on the
/// waker.
///
/// Note that on multiple calls to `poll_send_ready` or `poll_send`, only
/// the `Waker` from the `Context` passed to the most recent call is
/// scheduled to receive a wakeup. (However, `poll_recv_ready` retains a
/// second, independent waker.)
///
/// This function is intended for cases where creating and pinning a future
/// via [`writable`] is not feasible. Where possible, using [`writable`] is
/// preferred, as this supports polling from multiple tasks at once.
///
/// # Return value
///
/// The function returns:
///
/// * `Poll::Pending` if the udp stream is not ready for writing.
/// * `Poll::Ready(Ok(()))` if the udp stream is ready for writing.
/// * `Poll::Ready(Err(e))` if an error is encountered.
///
/// # Errors
///
/// This function may encounter any standard I/O error except `WouldBlock`.
///
/// [`writable`]: method@Self::writable
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.io.registration().poll_write_ready(cx).map_ok(|_| ())
}
/// Sends data on the socket to the remote address that the socket is
/// connected to.
///
@@ -516,7 +549,7 @@ impl UdpSocket {
.poll_write_io(cx, || self.io.send(buf))
}
/// Try to send data on the socket to the remote address to which it is
/// Tries to send data on the socket to the remote address to which it is
/// connected.
///
/// When the socket buffer is full, `Err(io::ErrorKind::WouldBlock)` is
@@ -570,7 +603,7 @@ impl UdpSocket {
.try_io(Interest::WRITABLE, || self.io.send(buf))
}
/// Wait for the socket to become readable.
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_recv()`.
@@ -630,6 +663,39 @@ impl UdpSocket {
Ok(())
}
/// Polls for read/receive readiness.
///
/// If the udp stream is not currently ready for receiving, this method will
/// store a clone of the `Waker` from the provided `Context`. When the udp
/// socket becomes ready for reading, `Waker::wake` will be called on the
/// waker.
///
/// Note that on multiple calls to `poll_recv_ready`, `poll_recv` or
/// `poll_peek`, only the `Waker` from the `Context` passed to the most
/// recent call is scheduled to receive a wakeup. (However,
/// `poll_send_ready` retains a second, independent waker.)
///
/// This function is intended for cases where creating and pinning a future
/// via [`readable`] is not feasible. Where possible, using [`readable`] is
/// preferred, as this supports polling from multiple tasks at once.
///
/// # Return value
///
/// The function returns:
///
/// * `Poll::Pending` if the udp stream is not ready for reading.
/// * `Poll::Ready(Ok(()))` if the udp stream is ready for reading.
/// * `Poll::Ready(Err(e))` if an error is encountered.
///
/// # Errors
///
/// This function may encounter any standard I/O error except `WouldBlock`.
///
/// [`readable`]: method@Self::readable
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.io.registration().poll_read_ready(cx).map_ok(|_| ())
}
/// Receives a single datagram message on the socket from the remote address
/// to which it is connected. On success, returns the number of bytes read.
///
@@ -715,7 +781,7 @@ impl UdpSocket {
Poll::Ready(Ok(()))
}
/// Try to receive a single datagram message on the socket from the remote
/// Tries to receive a single datagram message on the socket from the remote
/// address to which it is connected. On success, returns the number of
/// bytes read.
///
@@ -772,7 +838,7 @@ impl UdpSocket {
}
cfg_io_util! {
/// Try to receive data from the stream into the provided buffer, advancing the
/// Tries to receive data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// The function must be called with valid byte array buf of sufficient size
@@ -837,7 +903,7 @@ impl UdpSocket {
})
}
/// Try to receive a single datagram message on the socket. On success,
/// Tries to receive a single datagram message on the socket. On success,
/// returns the number of bytes read and the origin.
///
/// The function must be called with valid byte array buf of sufficient size
@@ -978,7 +1044,7 @@ impl UdpSocket {
.poll_write_io(cx, || self.io.send_to(buf, target))
}
/// Try to send data on the socket to the given address, but if the send is
/// Tries to send data on the socket to the given address, but if the send is
/// blocked this will return right away.
///
/// This function is usually paired with `writable()`.
@@ -1116,7 +1182,7 @@ impl UdpSocket {
Poll::Ready(Ok(addr))
}
/// Try to receive a single datagram message on the socket. On success,
/// Tries to receive a single datagram message on the socket. On success,
/// returns the number of bytes read and the origin.
///
/// The function must be called with valid byte array buf of sufficient size
@@ -1170,7 +1236,7 @@ impl UdpSocket {
.try_io(Interest::READABLE, || self.io.recv_from(buf))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
+77 -11
View File
@@ -96,7 +96,7 @@ cfg_net_unix! {
}
impl UnixDatagram {
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_recv()` or `try_send()`. It
/// can be used to concurrently recv / send to the same socket on a single
@@ -169,7 +169,7 @@ impl UnixDatagram {
Ok(event.ready)
}
/// Wait for the socket to become writable.
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is
/// usually paired with `try_send()` or `try_send_to()`.
@@ -226,7 +226,40 @@ impl UnixDatagram {
Ok(())
}
/// Wait for the socket to become readable.
/// Polls for write/send readiness.
///
/// If the socket is not currently ready for sending, this method will
/// store a clone of the `Waker` from the provided `Context`. When the socket
/// becomes ready for sending, `Waker::wake` will be called on the
/// waker.
///
/// Note that on multiple calls to `poll_send_ready` or `poll_send`, only
/// the `Waker` from the `Context` passed to the most recent call is
/// scheduled to receive a wakeup. (However, `poll_recv_ready` retains a
/// second, independent waker.)
///
/// This function is intended for cases where creating and pinning a future
/// via [`writable`] is not feasible. Where possible, using [`writable`] is
/// preferred, as this supports polling from multiple tasks at once.
///
/// # Return value
///
/// The function returns:
///
/// * `Poll::Pending` if the socket is not ready for writing.
/// * `Poll::Ready(Ok(()))` if the socket is ready for writing.
/// * `Poll::Ready(Err(e))` if an error is encountered.
///
/// # Errors
///
/// This function may encounter any standard I/O error except `WouldBlock`.
///
/// [`writable`]: method@Self::writable
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.io.registration().poll_write_ready(cx).map_ok(|_| ())
}
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_recv()`.
@@ -289,6 +322,39 @@ impl UnixDatagram {
Ok(())
}
/// Polls for read/receive readiness.
///
/// If the socket is not currently ready for receiving, this method will
/// store a clone of the `Waker` from the provided `Context`. When the
/// socket becomes ready for reading, `Waker::wake` will be called on the
/// waker.
///
/// Note that on multiple calls to `poll_recv_ready`, `poll_recv` or
/// `poll_peek`, only the `Waker` from the `Context` passed to the most
/// recent call is scheduled to receive a wakeup. (However,
/// `poll_send_ready` retains a second, independent waker.)
///
/// This function is intended for cases where creating and pinning a future
/// via [`readable`] is not feasible. Where possible, using [`readable`] is
/// preferred, as this supports polling from multiple tasks at once.
///
/// # Return value
///
/// The function returns:
///
/// * `Poll::Pending` if the socket is not ready for reading.
/// * `Poll::Ready(Ok(()))` if the socket is ready for reading.
/// * `Poll::Ready(Err(e))` if an error is encountered.
///
/// # Errors
///
/// This function may encounter any standard I/O error except `WouldBlock`.
///
/// [`readable`]: method@Self::readable
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.io.registration().poll_read_ready(cx).map_ok(|_| ())
}
/// Creates a new `UnixDatagram` bound to the specified path.
///
/// # Examples
@@ -397,7 +463,7 @@ impl UnixDatagram {
Ok(UnixDatagram { io })
}
/// Turn a [`tokio::net::UnixDatagram`] into a [`std::os::unix::net::UnixDatagram`].
/// Turns a [`tokio::net::UnixDatagram`] into a [`std::os::unix::net::UnixDatagram`].
///
/// The returned [`std::os::unix::net::UnixDatagram`] will have nonblocking
/// mode set as `true`. Use [`set_nonblocking`] to change the blocking mode
@@ -548,7 +614,7 @@ impl UnixDatagram {
.await
}
/// Try to send a datagram to the peer without waiting.
/// Tries to send a datagram to the peer without waiting.
///
/// # Examples
///
@@ -592,7 +658,7 @@ impl UnixDatagram {
.try_io(Interest::WRITABLE, || self.io.send(buf))
}
/// Try to send a datagram to the peer without waiting.
/// Tries to send a datagram to the peer without waiting.
///
/// # Examples
///
@@ -678,7 +744,7 @@ impl UnixDatagram {
.await
}
/// Try to receive a datagram from the peer without waiting.
/// Tries to receive a datagram from the peer without waiting.
///
/// # Examples
///
@@ -729,7 +795,7 @@ impl UnixDatagram {
}
cfg_io_util! {
/// Try to receive data from the socket without waiting.
/// Tries to receive data from the socket without waiting.
///
/// # Examples
///
@@ -790,7 +856,7 @@ impl UnixDatagram {
Ok((n, SocketAddr(addr)))
}
/// Try to read data from the stream into the provided buffer, advancing the
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// # Examples
@@ -1091,7 +1157,7 @@ impl UnixDatagram {
Poll::Ready(Ok(()))
}
/// Try to receive data from the socket without waiting.
/// Tries to receive data from the socket without waiting.
///
/// # Examples
///
@@ -1143,7 +1209,7 @@ impl UnixDatagram {
Ok((n, SocketAddr(addr)))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
+1 -1
View File
@@ -88,7 +88,7 @@ impl UnixListener {
Ok(UnixListener { io })
}
/// Turn a [`tokio::net::UnixListener`] into a [`std::os::unix::net::UnixListener`].
/// Turns a [`tokio::net::UnixListener`] into a [`std::os::unix::net::UnixListener`].
///
/// The returned [`std::os::unix::net::UnixListener`] will have nonblocking mode
/// set as `true`. Use [`set_nonblocking`] to change the blocking mode if needed.
+1 -1
View File
@@ -1,4 +1,4 @@
//! Unix domain socket utility types
//! Unix domain socket utility types.
// This module does not currently provide any public API, but it was
// unintentionally defined as a public module. Hide it from the documentation
+206 -1
View File
@@ -8,14 +8,19 @@
//! split has no associated overhead and enforces all invariants at the type
//! level.
use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::io::{AsyncRead, AsyncWrite, Interest, ReadBuf, Ready};
use crate::net::UnixStream;
use crate::net::unix::SocketAddr;
use std::io;
use std::net::Shutdown;
use std::pin::Pin;
use std::task::{Context, Poll};
cfg_io_util! {
use bytes::BufMut;
}
/// Borrowed read half of a [`UnixStream`], created by [`split`].
///
/// Reading from a `ReadHalf` is usually done using the convenience methods found on the
@@ -47,6 +52,206 @@ pub(crate) fn split(stream: &mut UnixStream) -> (ReadHalf<'_>, WriteHalf<'_>) {
(ReadHalf(stream), WriteHalf(stream))
}
impl ReadHalf<'_> {
/// Wait for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.0.ready(interest).await
}
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn readable(&self) -> io::Result<()> {
self.0.readable().await
}
/// Tries to read data from the stream into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.try_read(buf)
}
cfg_io_util! {
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
self.0.try_read_buf(buf)
}
}
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
/// written to possibly being only partially filled. This method behaves
/// equivalently to a single call to [`try_read()`] with concatenated
/// buffers.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_vectored()` is non-blocking, the buffer does not have to be
/// stored by the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`try_read()`]: Self::try_read()
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.try_read_vectored(bufs)
}
/// Returns the socket address of the remote half of this connection.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
/// Returns the socket address of the local half of this connection.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
}
impl WriteHalf<'_> {
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.0.ready(interest).await
}
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn writable(&self) -> io::Result<()> {
self.0.writable().await
}
/// Tries to write a buffer to the stream, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
/// only part of the buffer may be written.
///
/// This function is usually paired with `writable()`.
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.try_write(buf)
}
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
/// from possible being only partially consumed. This method behaves
/// equivalently to a single call to [`try_write()`] with concatenated
/// buffers.
///
/// This function is usually paired with `writable()`.
///
/// [`try_write()`]: Self::try_write()
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write_vectored(&self, buf: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.try_write_vectored(buf)
}
/// Returns the socket address of the remote half of this connection.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
/// Returns the socket address of the local half of this connection.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
}
impl AsyncRead for ReadHalf<'_> {
fn poll_read(
self: Pin<&mut Self>,
+204 -2
View File
@@ -8,9 +8,10 @@
//! split has no associated overhead and enforces all invariants at the type
//! level.
use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
use crate::io::{AsyncRead, AsyncWrite, Interest, ReadBuf, Ready};
use crate::net::UnixStream;
use crate::net::unix::SocketAddr;
use std::error::Error;
use std::net::Shutdown;
use std::pin::Pin;
@@ -18,6 +19,10 @@ use std::sync::Arc;
use std::task::{Context, Poll};
use std::{fmt, io};
cfg_io_util! {
use bytes::BufMut;
}
/// Owned read half of a [`UnixStream`], created by [`into_split`].
///
/// Reading from an `OwnedReadHalf` is usually done using the convenience methods found
@@ -102,6 +107,124 @@ impl OwnedReadHalf {
pub fn reunite(self, other: OwnedWriteHalf) -> Result<UnixStream, ReuniteError> {
reunite(self, other)
}
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.inner.ready(interest).await
}
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn readable(&self) -> io::Result<()> {
self.inner.readable().await
}
/// Tries to read data from the stream into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.try_read(buf)
}
cfg_io_util! {
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_buf()` is non-blocking, the buffer does not have to be stored by
/// the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> io::Result<usize> {
self.inner.try_read_buf(buf)
}
}
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
/// written to possibly being only partially filled. This method behaves
/// equivalently to a single call to [`try_read()`] with concatenated
/// buffers.
///
/// Receives any pending data from the socket but does not wait for new data
/// to arrive. On success, returns the number of bytes read. Because
/// `try_read_vectored()` is non-blocking, the buffer does not have to be
/// stored by the async task and can exist entirely on the stack.
///
/// Usually, [`readable()`] or [`ready()`] is used with this function.
///
/// [`try_read()`]: Self::try_read()
/// [`readable()`]: Self::readable()
/// [`ready()`]: Self::ready()
///
/// # Return
///
/// If data is successfully read, `Ok(n)` is returned, where `n` is the
/// number of bytes read. `Ok(0)` indicates the stream's read half is closed
/// and will no longer yield data. If the stream is not ready to read data
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.try_read_vectored(bufs)
}
/// Returns the socket address of the remote half of this connection.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
}
/// Returns the socket address of the local half of this connection.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
}
impl AsyncRead for OwnedReadHalf {
@@ -124,13 +247,92 @@ impl OwnedWriteHalf {
reunite(other, self)
}
/// Destroy the write half, but don't close the write half of the stream
/// Destroys the write half, but don't close the write half of the stream
/// until the read half is dropped. If the read half has already been
/// dropped, this closes the stream.
pub fn forget(mut self) {
self.shutdown_on_drop = false;
drop(self);
}
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
/// task without splitting the socket.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to read or write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
self.inner.ready(interest).await
}
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
///
/// # Cancel safety
///
/// This method is cancel safe. Once a readiness event occurs, the method
/// will continue to return immediately until the readiness event is
/// consumed by an attempt to write that fails with `WouldBlock` or
/// `Poll::Pending`.
pub async fn writable(&self) -> io::Result<()> {
self.inner.writable().await
}
/// Tries to write a buffer to the stream, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
/// only part of the buffer may be written.
///
/// This function is usually paired with `writable()`.
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write(&self, buf: &[u8]) -> io::Result<usize> {
self.inner.try_write(buf)
}
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
/// from possible being only partially consumed. This method behaves
/// equivalently to a single call to [`try_write()`] with concatenated
/// buffers.
///
/// This function is usually paired with `writable()`.
///
/// [`try_write()`]: Self::try_write()
///
/// # Return
///
/// If data is successfully written, `Ok(n)` is returned, where `n` is the
/// number of bytes written. If the stream is not ready to write data,
/// `Err(io::ErrorKind::WouldBlock)` is returned.
pub fn try_write_vectored(&self, buf: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.inner.try_write_vectored(buf)
}
/// Returns the socket address of the remote half of this connection.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
}
/// Returns the socket address of the local half of this connection.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
}
impl Drop for OwnedWriteHalf {
+40 -10
View File
@@ -59,7 +59,7 @@ impl UnixStream {
Ok(stream)
}
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same socket on a single
@@ -133,7 +133,7 @@ impl UnixStream {
Ok(event.ready)
}
/// Wait for the socket to become readable.
/// Waits for the socket to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
@@ -290,7 +290,7 @@ impl UnixStream {
.try_io(Interest::READABLE, || (&*self.io).read(buf))
}
/// Try to read data from the stream into the provided buffers, returning
/// Tries to read data from the stream into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
@@ -369,7 +369,7 @@ impl UnixStream {
}
cfg_io_util! {
/// Try to read data from the stream into the provided buffer, advancing the
/// Tries to read data from the stream into the provided buffer, advancing the
/// buffer's internal cursor, returning how many bytes were read.
///
/// Receives any pending data from the socket but does not wait for new data
@@ -449,7 +449,7 @@ impl UnixStream {
}
}
/// Wait for the socket to become writable.
/// Waits for the socket to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
@@ -535,7 +535,7 @@ impl UnixStream {
self.io.registration().poll_write_ready(cx).map_ok(|_| ())
}
/// Try to write a buffer to the stream, returning how many bytes were
/// Tries to write a buffer to the stream, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
@@ -591,7 +591,7 @@ impl UnixStream {
.try_io(Interest::WRITABLE, || (&*self.io).write(buf))
}
/// Try to write several buffers to the stream, returning how many bytes
/// Tries to write several buffers to the stream, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
@@ -653,7 +653,7 @@ impl UnixStream {
.try_io(Interest::WRITABLE, || (&*self.io).write_vectored(buf))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
@@ -709,7 +709,7 @@ impl UnixStream {
Ok(UnixStream { io })
}
/// Turn a [`tokio::net::UnixStream`] into a [`std::os::unix::net::UnixStream`].
/// Turns a [`tokio::net::UnixStream`] into a [`std::os::unix::net::UnixStream`].
///
/// The returned [`std::os::unix::net::UnixStream`] will have nonblocking
/// mode set as `true`. Use [`set_nonblocking`] to change the blocking
@@ -773,11 +773,41 @@ impl UnixStream {
}
/// Returns the socket address of the local half of this connection.
///
/// # Examples
///
/// ```no_run
/// use tokio::net::UnixStream;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let dir = tempfile::tempdir().unwrap();
/// let bind_path = dir.path().join("bind_path");
/// let stream = UnixStream::connect(bind_path).await?;
///
/// println!("{:?}", stream.local_addr()?);
/// # Ok(())
/// # }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io.local_addr().map(SocketAddr)
}
/// Returns the socket address of the remote half of this connection.
///
/// # Examples
///
/// ```no_run
/// use tokio::net::UnixStream;
///
/// # async fn dox() -> Result<(), Box<dyn std::error::Error>> {
/// let dir = tempfile::tempdir().unwrap();
/// let bind_path = dir.path().join("bind_path");
/// let stream = UnixStream::connect(bind_path).await?;
///
/// println!("{:?}", stream.peer_addr()?);
/// # Ok(())
/// # }
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io.peer_addr().map(SocketAddr)
}
@@ -804,7 +834,7 @@ impl UnixStream {
// These lifetime markers also appear in the generated documentation, and make
// it more clear that this is a *borrowed* split.
#[allow(clippy::needless_lifetimes)]
/// Split a `UnixStream` into a read half and a write half, which can be used
/// Splits a `UnixStream` into a read half and a write half, which can be used
/// to read and write the stream concurrently.
///
/// This method is more efficient than [`into_split`], but the halves cannot be
+4 -4
View File
@@ -1,13 +1,13 @@
use libc::{gid_t, pid_t, uid_t};
/// Credentials of a process
/// Credentials of a process.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UCred {
/// PID (process ID) of the process
/// PID (process ID) of the process.
pid: Option<pid_t>,
/// UID (user ID) of the process
/// UID (user ID) of the process.
uid: uid_t,
/// GID (group ID) of the process
/// GID (group ID) of the process.
gid: gid_t,
}
+23 -23
View File
@@ -105,7 +105,7 @@ pub struct NamedPipeServer {
}
impl NamedPipeServer {
/// Construct a new named pipe server from the specified raw handle.
/// Constructs a new named pipe server from the specified raw handle.
///
/// This function will consume ownership of the handle given, passing
/// responsibility for closing the handle to the returned object.
@@ -234,7 +234,7 @@ impl NamedPipeServer {
self.io.disconnect()
}
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same pipe on a single
@@ -301,7 +301,7 @@ impl NamedPipeServer {
Ok(event.ready)
}
/// Wait for the pipe to become readable.
/// Waits for the pipe to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
@@ -383,7 +383,7 @@ impl NamedPipeServer {
self.io.registration().poll_read_ready(cx).map_ok(|_| ())
}
/// Try to read data from the pipe into the provided buffer, returning how
/// Tries to read data from the pipe into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the pipe but does not wait for new data
@@ -450,7 +450,7 @@ impl NamedPipeServer {
.try_io(Interest::READABLE, || (&*self.io).read(buf))
}
/// Try to read data from the pipe into the provided buffers, returning
/// Tries to read data from the pipe into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
@@ -528,7 +528,7 @@ impl NamedPipeServer {
.try_io(Interest::READABLE, || (&*self.io).read_vectored(bufs))
}
/// Wait for the pipe to become writable.
/// Waits for the pipe to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
@@ -606,7 +606,7 @@ impl NamedPipeServer {
self.io.registration().poll_write_ready(cx).map_ok(|_| ())
}
/// Try to write a buffer to the pipe, returning how many bytes were
/// Tries to write a buffer to the pipe, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
@@ -662,7 +662,7 @@ impl NamedPipeServer {
.try_io(Interest::WRITABLE, || (&*self.io).write(buf))
}
/// Try to write several buffers to the pipe, returning how many bytes
/// Tries to write several buffers to the pipe, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
@@ -724,7 +724,7 @@ impl NamedPipeServer {
.try_io(Interest::WRITABLE, || (&*self.io).write_vectored(buf))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
@@ -846,7 +846,7 @@ pub struct NamedPipeClient {
}
impl NamedPipeClient {
/// Construct a new named pipe client from the specified raw handle.
/// Constructs a new named pipe client from the specified raw handle.
///
/// This function will consume ownership of the handle given, passing
/// responsibility for closing the handle to the returned object.
@@ -896,7 +896,7 @@ impl NamedPipeClient {
unsafe { named_pipe_info(self.io.as_raw_handle()) }
}
/// Wait for any of the requested ready states.
/// Waits for any of the requested ready states.
///
/// This function is usually paired with `try_read()` or `try_write()`. It
/// can be used to concurrently read / write to the same pipe on a single
@@ -962,7 +962,7 @@ impl NamedPipeClient {
Ok(event.ready)
}
/// Wait for the pipe to become readable.
/// Waits for the pipe to become readable.
///
/// This function is equivalent to `ready(Interest::READABLE)` and is usually
/// paired with `try_read()`.
@@ -1043,7 +1043,7 @@ impl NamedPipeClient {
self.io.registration().poll_read_ready(cx).map_ok(|_| ())
}
/// Try to read data from the pipe into the provided buffer, returning how
/// Tries to read data from the pipe into the provided buffer, returning how
/// many bytes were read.
///
/// Receives any pending data from the pipe but does not wait for new data
@@ -1109,7 +1109,7 @@ impl NamedPipeClient {
.try_io(Interest::READABLE, || (&*self.io).read(buf))
}
/// Try to read data from the pipe into the provided buffers, returning
/// Tries to read data from the pipe into the provided buffers, returning
/// how many bytes were read.
///
/// Data is copied to fill each buffer in order, with the final buffer
@@ -1186,7 +1186,7 @@ impl NamedPipeClient {
.try_io(Interest::READABLE, || (&*self.io).read_vectored(bufs))
}
/// Wait for the pipe to become writable.
/// Waits for the pipe to become writable.
///
/// This function is equivalent to `ready(Interest::WRITABLE)` and is usually
/// paired with `try_write()`.
@@ -1263,7 +1263,7 @@ impl NamedPipeClient {
self.io.registration().poll_write_ready(cx).map_ok(|_| ())
}
/// Try to write a buffer to the pipe, returning how many bytes were
/// Tries to write a buffer to the pipe, returning how many bytes were
/// written.
///
/// The function will attempt to write the entire contents of `buf`, but
@@ -1318,7 +1318,7 @@ impl NamedPipeClient {
.try_io(Interest::WRITABLE, || (&*self.io).write(buf))
}
/// Try to write several buffers to the pipe, returning how many bytes
/// Tries to write several buffers to the pipe, returning how many bytes
/// were written.
///
/// Data is written from each buffer in order, with the final buffer read
@@ -1379,7 +1379,7 @@ impl NamedPipeClient {
.try_io(Interest::WRITABLE, || (&*self.io).write_vectored(buf))
}
/// Try to read or write from the socket using a user-provided IO operation.
/// Tries to read or write from the socket using a user-provided IO operation.
///
/// If the socket is ready, the provided closure is called. The closure
/// should attempt to perform IO operation from the socket by manually
@@ -1882,7 +1882,7 @@ impl ServerOptions {
self
}
/// Create the named pipe identified by `addr` for use as a server.
/// Creates the named pipe identified by `addr` for use as a server.
///
/// This uses the [`CreateNamedPipe`] function.
///
@@ -1913,7 +1913,7 @@ impl ServerOptions {
unsafe { self.create_with_security_attributes_raw(addr, ptr::null_mut()) }
}
/// Create the named pipe identified by `addr` for use as a server.
/// Creates the named pipe identified by `addr` for use as a server.
///
/// This is the same as [`create`] except that it supports providing the raw
/// pointer to a structure of [`SECURITY_ATTRIBUTES`] which will be passed
@@ -2042,7 +2042,7 @@ impl ClientOptions {
self
}
/// Open the named pipe identified by `addr`.
/// Opens the named pipe identified by `addr`.
///
/// This opens the client using [`CreateFile`] with the
/// `dwCreationDisposition` option set to `OPEN_EXISTING`.
@@ -2099,7 +2099,7 @@ impl ClientOptions {
unsafe { self.open_with_security_attributes_raw(addr, ptr::null_mut()) }
}
/// Open the named pipe identified by `addr`.
/// Opens the named pipe identified by `addr`.
///
/// This is the same as [`open`] except that it supports providing the raw
/// pointer to a structure of [`SECURITY_ATTRIBUTES`] which will be passed
@@ -2201,7 +2201,7 @@ pub struct PipeInfo {
pub in_buffer_size: u32,
}
/// Encode an address so that it is a null-terminated wide string.
/// Encodes an address so that it is a null-terminated wide string.
fn encode_addr(addr: impl AsRef<OsStr>) -> Box<[u16]> {
let len = addr.as_ref().encode_wide().count();
let mut vec = Vec::with_capacity(len + 1);
+6 -6
View File
@@ -45,12 +45,12 @@ use std::fmt::Debug;
use std::sync::Arc;
use std::time::Duration;
/// Block the current thread.
/// Blocks the current thread.
pub(crate) trait Park {
/// Unpark handle type for the `Park` implementation.
type Unpark: Unpark;
/// Error returned by `park`
/// Error returned by `park`.
type Error: Debug;
/// Gets a new `Unpark` handle associated with this `Park` instance.
@@ -66,7 +66,7 @@ pub(crate) trait Park {
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Park` implementation
/// `Park` implementation.
fn park(&mut self) -> Result<(), Self::Error>;
/// Parks the current thread for at most `duration`.
@@ -82,10 +82,10 @@ pub(crate) trait Park {
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Park` implementation
/// `Park` implementation.
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>;
/// Release all resources holded by the parker for proper leak-free shutdown
/// Releases all resources holded by the parker for proper leak-free shutdown.
fn shutdown(&mut self);
}
@@ -100,7 +100,7 @@ pub(crate) trait Unpark: Sync + Send + 'static {
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Unpark` implementation
/// `Unpark` implementation.
fn unpark(&self);
}
+3 -3
View File
@@ -76,7 +76,7 @@ impl Park for ParkThread {
// ==== impl Inner ====
impl Inner {
/// Park the current thread for at most `dur`.
/// Parks the current thread for at most `dur`.
fn park(&self) {
// If we were previously notified then we consume this notification and
// return quickly.
@@ -227,7 +227,7 @@ pub(crate) struct CachedParkThread {
}
impl CachedParkThread {
/// Create a new `ParkThread` handle for the current thread.
/// Creates a new `ParkThread` handle for the current thread.
///
/// This type cannot be moved to other threads, so it should be created on
/// the thread that the caller intends to park.
@@ -241,7 +241,7 @@ impl CachedParkThread {
self.with_current(|park_thread| park_thread.unpark())
}
/// Get a reference to the `ParkThread` handle for this thread.
/// Gets a reference to the `ParkThread` handle for this thread.
fn with_current<F, R>(&self, f: F) -> Result<R, ParkError>
where
F: FnOnce(&ParkThread) -> R,
+4 -4
View File
@@ -578,7 +578,7 @@ impl Command {
self
}
/// Set executable argument
/// Sets executable argument.
///
/// Set the first process argument, `argv[0]`, to something other than the
/// default executable path.
@@ -1173,7 +1173,7 @@ pub struct ChildStderr {
}
impl ChildStdin {
/// Create an asynchronous `ChildStdin` from a synchronous one.
/// Creates an asynchronous `ChildStdin` from a synchronous one.
///
/// # Errors
///
@@ -1188,7 +1188,7 @@ impl ChildStdin {
}
impl ChildStdout {
/// Create an asynchronous `ChildStderr` from a synchronous one.
/// Creates an asynchronous `ChildStderr` from a synchronous one.
///
/// # Errors
///
@@ -1203,7 +1203,7 @@ impl ChildStdout {
}
impl ChildStderr {
/// Create an asynchronous `ChildStderr` from a synchronous one.
/// Creates an asynchronous `ChildStderr` from a synchronous one.
///
/// # Errors
///
+1 -1
View File
@@ -1,6 +1,6 @@
#![cfg_attr(not(feature = "rt"), allow(dead_code))]
//! Process driver
//! Process driver.
use crate::park::Park;
use crate::process::unix::GlobalOrphanQueue;
+1 -1
View File
@@ -1,4 +1,4 @@
//! Unix handling of child processes
//! Unix handling of child processes.
//!
//! Right now the only "fancy" thing about this is how we implement the
//! `Future` implementation on `Child` to get the exit status. Unix offers
+11 -11
View File
@@ -12,7 +12,7 @@ use std::cell::RefCell;
use std::collections::VecDeque;
use std::fmt;
use std::future::Future;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::sync::atomic::Ordering::{AcqRel, Release};
use std::sync::Arc;
use std::task::Poll::{Pending, Ready};
use std::time::Duration;
@@ -213,19 +213,17 @@ impl<P: Park> BasicScheduler<P> {
}
impl<P: Park> Inner<P> {
/// Block on the future provided and drive the runtime's driver.
/// Blocks on the provided future and drives the runtime's driver.
fn block_on<F: Future>(&mut self, future: F) -> F::Output {
enter(self, |scheduler, context| {
let _enter = crate::runtime::enter(false);
let waker = scheduler.spawner.waker_ref();
let mut cx = std::task::Context::from_waker(&waker);
let mut polled = false;
pin!(future);
'outer: loop {
if scheduler.spawner.was_woken() || !polled {
polled = true;
if scheduler.spawner.reset_woken() {
scheduler.stats.incr_poll_count();
if let Ready(v) = crate::coop::budget(|| future.as_mut().poll(&mut cx)) {
return v;
@@ -301,8 +299,8 @@ impl<P: Park> Inner<P> {
}
}
/// Enter the scheduler context. This sets the queue and other necessary
/// scheduler state in the thread-local
/// Enters the scheduler context. This sets the queue and other necessary
/// scheduler state in the thread-local.
fn enter<F, R, P>(scheduler: &mut Inner<P>, f: F) -> R
where
F: FnOnce(&mut Inner<P>, &Context) -> R,
@@ -418,13 +416,15 @@ impl Spawner {
}
fn waker_ref(&self) -> WakerRef<'_> {
// clear the woken bit
self.shared.woken.swap(false, AcqRel);
// Set woken to true when enter block_on, ensure outer future
// be polled for the first time when enter loop
self.shared.woken.store(true, Release);
waker_ref(&self.shared)
}
fn was_woken(&self) -> bool {
self.shared.woken.load(Acquire)
// reset woken to false and return original value
pub(crate) fn reset_woken(&self) -> bool {
self.shared.woken.swap(false, AcqRel)
}
}
+9 -9
View File
@@ -25,28 +25,28 @@ pub(crate) struct Spawner {
}
struct Inner {
/// State shared between worker threads
/// State shared between worker threads.
shared: Mutex<Shared>,
/// Pool threads wait on this.
condvar: Condvar,
/// Spawned threads use this name
/// Spawned threads use this name.
thread_name: ThreadNameFn,
/// Spawned thread stack size
/// Spawned thread stack size.
stack_size: Option<usize>,
/// Call after a thread starts
/// Call after a thread starts.
after_start: Option<Callback>,
/// Call before a thread stops
/// Call before a thread stops.
before_stop: Option<Callback>,
// Maximum number of threads
// Maximum number of threads.
thread_cap: usize,
// Customizable wait timeout
// Customizable wait timeout.
keep_alive: Duration,
}
@@ -67,7 +67,7 @@ struct Shared {
/// calling shutdown handles joining on these.
worker_threads: HashMap<usize, thread::JoinHandle<()>>,
/// This is a counter used to iterate worker_threads in a consistent order (for loom's
/// benefit)
/// benefit).
worker_thread_index: usize,
}
@@ -75,7 +75,7 @@ type Task = task::UnownedTask<NoopSchedule>;
const KEEP_ALIVE: Duration = Duration::from_secs(10);
/// Run the provided function on an executor dedicated to blocking operations.
/// Runs the provided function on an executor dedicated to blocking operations.
pub(crate) fn spawn_blocking<F, R>(func: F) -> JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
+2 -2
View File
@@ -10,7 +10,7 @@ use std::time::Duration;
#[derive(Debug, Clone)]
pub(super) struct Sender {
tx: Arc<oneshot::Sender<()>>,
_tx: Arc<oneshot::Sender<()>>,
}
#[derive(Debug)]
@@ -20,7 +20,7 @@ pub(super) struct Receiver {
pub(super) fn channel() -> (Sender, Receiver) {
let (tx, rx) = oneshot::channel();
let tx = Sender { tx: Arc::new(tx) };
let tx = Sender { _tx: Arc::new(tx) };
let rx = Receiver { rx };
(tx, rx)
+2 -2
View File
@@ -2,13 +2,13 @@ use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
/// Converts a function to a future that completes on poll
/// Converts a function to a future that completes on poll.
pub(crate) struct BlockingTask<T> {
func: Option<T>,
}
impl<T> BlockingTask<T> {
/// Initializes a new blocking task from the given function
/// Initializes a new blocking task from the given function.
pub(crate) fn new(func: T) -> BlockingTask<T> {
BlockingTask { func: Some(func) }
}
+1 -1
View File
@@ -51,7 +51,7 @@ cfg_rt! {
}
}
/// Set this [`Handle`] as the current active [`Handle`].
/// Sets this [`Handle`] as the current active [`Handle`].
///
/// [`Handle`]: Handle
pub(crate) fn enter(new: Handle) -> EnterGuard {
+1 -1
View File
@@ -92,7 +92,7 @@ cfg_rt_multi_thread! {
}
cfg_rt! {
/// Disallow blocking in the current runtime context until the guard is dropped.
/// Disallows blocking in the current runtime context until the guard is dropped.
pub(crate) fn disallow_blocking() -> DisallowBlockingGuard {
let reset = ENTERED.with(|c| {
if let EnterContext::Entered {
+25 -10
View File
@@ -4,6 +4,7 @@ use crate::runtime::{blocking, context, driver, Spawner};
use crate::util::error::CONTEXT_MISSING_ERROR;
use std::future::Future;
use std::marker::PhantomData;
use std::{error, fmt};
/// Handle to the runtime.
@@ -17,15 +18,25 @@ pub struct Handle {
pub(super) spawner: Spawner,
/// Handles to the I/O drivers
#[cfg_attr(
not(any(feature = "net", feature = "process", all(unix, feature = "signal"))),
allow(dead_code)
)]
pub(super) io_handle: driver::IoHandle,
/// Handles to the signal drivers
#[cfg_attr(
not(any(feature = "signal", all(unix, feature = "process"))),
allow(dead_code)
)]
pub(super) signal_handle: driver::SignalHandle,
/// Handles to the time drivers
#[cfg_attr(not(feature = "time"), allow(dead_code))]
pub(super) time_handle: driver::TimeHandle,
/// Source of `Instant::now()`
#[cfg_attr(not(all(feature = "time", feature = "test-util")), allow(dead_code))]
pub(super) clock: driver::Clock,
/// Blocking pool spawner
@@ -41,12 +52,12 @@ pub struct Handle {
#[derive(Debug)]
#[must_use = "Creating and dropping a guard does nothing"]
pub struct EnterGuard<'a> {
handle: &'a Handle,
guard: context::EnterGuard,
_guard: context::EnterGuard,
_handle_lifetime: PhantomData<&'a Handle>,
}
impl Handle {
/// Enter the runtime context. This allows you to construct types that must
/// Enters the runtime context. This allows you to construct types that must
/// have an executor available on creation such as [`Sleep`] or [`TcpStream`].
/// It will also allow you to call methods such as [`tokio::spawn`].
///
@@ -55,12 +66,12 @@ impl Handle {
/// [`tokio::spawn`]: fn@crate::spawn
pub fn enter(&self) -> EnterGuard<'_> {
EnterGuard {
handle: self,
guard: context::enter(self.clone()),
_guard: context::enter(self.clone()),
_handle_lifetime: PhantomData,
}
}
/// Returns a `Handle` view over the currently running `Runtime`
/// Returns a `Handle` view over the currently running `Runtime`.
///
/// # Panic
///
@@ -119,7 +130,7 @@ impl Handle {
}
}
/// Spawn a future onto the Tokio runtime.
/// Spawns a future onto the Tokio runtime.
///
/// This spawns the given future onto the runtime's executor, usually a
/// thread pool. The thread pool is then responsible for polling the future
@@ -157,7 +168,7 @@ impl Handle {
self.spawner.spawn(future)
}
/// Run the provided function on an executor dedicated to blocking
/// Runs the provided function on an executor dedicated to blocking.
/// operations.
///
/// # Examples
@@ -182,7 +193,11 @@ impl Handle {
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
self.spawn_blocking_inner(func, None)
if cfg!(debug_assertions) && std::mem::size_of::<F>() > 2048 {
self.spawn_blocking_inner(Box::new(func), None)
} else {
self.spawn_blocking_inner(func, None)
}
}
#[cfg_attr(tokio_track_caller, track_caller)]
@@ -226,7 +241,7 @@ impl Handle {
handle
}
/// Run a future to completion on this `Handle`'s associated `Runtime`.
/// Runs a future to completion on this `Handle`'s associated `Runtime`.
///
/// This runs the given future on the current thread, blocking until it is
/// complete, and yielding its resolved result. Any tasks or timers which
+8 -8
View File
@@ -294,7 +294,7 @@ cfg_rt! {
type Callback = std::sync::Arc<dyn Fn() + Send + Sync>;
impl Runtime {
/// Create a new runtime instance with default configuration values.
/// Creates a new runtime instance with default configuration values.
///
/// This results in the multi threaded scheduler, I/O driver, and time driver being
/// initialized.
@@ -329,7 +329,7 @@ cfg_rt! {
Builder::new_multi_thread().enable_all().build()
}
/// Return a handle to the runtime's spawner.
/// Returns a handle to the runtime's spawner.
///
/// The returned handle can be used to spawn tasks that run on this runtime, and can
/// be cloned to allow moving the `Handle` to other threads.
@@ -350,7 +350,7 @@ cfg_rt! {
&self.handle
}
/// Spawn a future onto the Tokio runtime.
/// Spawns a future onto the Tokio runtime.
///
/// This spawns the given future onto the runtime's executor, usually a
/// thread pool. The thread pool is then responsible for polling the future
@@ -384,7 +384,7 @@ cfg_rt! {
self.handle.spawn(future)
}
/// Run the provided function on an executor dedicated to blocking operations.
/// Runs the provided function on an executor dedicated to blocking operations.
///
/// # Examples
///
@@ -409,7 +409,7 @@ cfg_rt! {
self.handle.spawn_blocking(func)
}
/// Run a future to completion on the Tokio runtime. This is the
/// Runs a future to completion on the Tokio runtime. This is the
/// runtime's entry point.
///
/// This runs the given future on the current thread, blocking until it is
@@ -464,7 +464,7 @@ cfg_rt! {
}
}
/// Enter the runtime context.
/// Enters the runtime context.
///
/// This allows you to construct types that must have an executor
/// available on creation such as [`Sleep`] or [`TcpStream`]. It will
@@ -500,7 +500,7 @@ cfg_rt! {
self.handle.enter()
}
/// Shutdown the runtime, waiting for at most `duration` for all spawned
/// Shuts down the runtime, waiting for at most `duration` for all spawned
/// task to shutdown.
///
/// Usually, dropping a `Runtime` handle is sufficient as tasks are able to
@@ -541,7 +541,7 @@ cfg_rt! {
self.blocking_pool.shutdown(Some(duration));
}
/// Shutdown the runtime, without waiting for any spawned tasks to shutdown.
/// Shuts down the runtime, without waiting for any spawned tasks to shutdown.
///
/// This can be useful if you want to drop a runtime from within another runtime.
/// Normally, dropping a runtime will block indefinitely for spawned blocking tasks
+8 -8
View File
@@ -44,22 +44,22 @@ pub(super) struct CoreStage<T: Future> {
///
/// Holds the future or output, depending on the stage of execution.
pub(super) struct Core<T: Future, S> {
/// Scheduler used to drive this future
/// Scheduler used to drive this future.
pub(super) scheduler: S,
/// Either the future or the output
/// Either the future or the output.
pub(super) stage: CoreStage<T>,
}
/// Crate public as this is also needed by the pool.
#[repr(C)]
pub(crate) struct Header {
/// Task state
/// Task state.
pub(super) state: State,
pub(super) owned: UnsafeCell<linked_list::Pointers<Header>>,
/// Pointer to next task, used with the injection queue
/// Pointer to next task, used with the injection queue.
pub(super) queue_next: UnsafeCell<Option<NonNull<Header>>>,
/// Table of function pointers for executing actions on the task.
@@ -133,7 +133,7 @@ impl<T: Future> CoreStage<T> {
self.stage.with_mut(f)
}
/// Poll the future
/// Polls the future.
///
/// # Safety
///
@@ -169,7 +169,7 @@ impl<T: Future> CoreStage<T> {
res
}
/// Drop the future
/// Drops the future.
///
/// # Safety
///
@@ -181,7 +181,7 @@ impl<T: Future> CoreStage<T> {
}
}
/// Store the task output
/// Stores the task output.
///
/// # Safety
///
@@ -193,7 +193,7 @@ impl<T: Future> CoreStage<T> {
}
}
/// Take the task output
/// Takes the task output.
///
/// # Safety
///
+2 -2
View File
@@ -29,12 +29,12 @@ impl JoinError {
}
}
/// Returns true if the error was caused by the task being cancelled
/// Returns true if the error was caused by the task being cancelled.
pub fn is_cancelled(&self) -> bool {
matches!(&self.repr, Repr::Cancelled)
}
/// Returns true if the error was caused by the task panicking
/// Returns true if the error was caused by the task panicking.
///
/// # Examples
///
+9 -9
View File
@@ -10,7 +10,7 @@ use std::panic;
use std::ptr::NonNull;
use std::task::{Context, Poll, Waker};
/// Typed raw task handle
/// Typed raw task handle.
pub(super) struct Harness<T: Future, S: 'static> {
cell: NonNull<Cell<T, S>>,
}
@@ -74,7 +74,7 @@ where
}
}
/// Poll the task and cancel it if necessary. This takes ownership of a
/// Polls the task and cancel it if necessary. This takes ownership of a
/// ref-count.
///
/// If the return value is Notified, the caller is given ownership of two
@@ -124,7 +124,7 @@ where
}
}
/// Forcibly shutdown the task
/// Forcibly shuts down the task.
///
/// Attempt to transition to `Running` in order to forcibly shutdown the
/// task. If the task is currently running or in a state of completion, then
@@ -192,7 +192,7 @@ where
}
}
/// Remotely abort the task.
/// Remotely aborts the task.
///
/// The caller should hold a ref-count, but we do not consume it.
///
@@ -280,7 +280,7 @@ where
// ====== internal ======
/// Complete the task. This method assumes that the state is RUNNING.
/// Completes the task. This method assumes that the state is RUNNING.
fn complete(self) {
// The future has completed and its output has been written to the task
// stage. We transition from running to complete.
@@ -310,7 +310,7 @@ where
}
}
/// Release the task from the scheduler. Returns the number of ref-counts
/// Releases the task from the scheduler. Returns the number of ref-counts
/// that should be decremented.
fn release(&self) -> usize {
// We don't actually increment the ref-count here, but the new task is
@@ -325,7 +325,7 @@ where
}
}
/// Create a new task that holds its own ref-count.
/// Creates a new task that holds its own ref-count.
///
/// # Safety
///
@@ -425,7 +425,7 @@ enum PollFuture {
Dealloc,
}
/// Cancel the task and store the appropriate error in the stage field.
/// Cancels the task and store the appropriate error in the stage field.
fn cancel_task<T: Future>(stage: &CoreStage<T>) {
// Drop the future from a panic guard.
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
@@ -442,7 +442,7 @@ fn cancel_task<T: Future>(stage: &CoreStage<T>) {
}
}
/// Poll the future. If the future completes, the output is written to the
/// Polls the future. If the future completes, the output is written to the
/// stage field.
fn poll_future<T: Future>(core: &CoreStage<T>, cx: Context<'_>) -> Poll<()> {
// Poll the future.
+6 -6
View File
@@ -11,7 +11,7 @@ use std::sync::atomic::Ordering::{Acquire, Release};
/// Growable, MPMC queue used to inject new tasks into the scheduler and as an
/// overflow queue when the local, fixed-size, array queue overflows.
pub(crate) struct Inject<T: 'static> {
/// Pointers to the head and tail of the queue
/// Pointers to the head and tail of the queue.
pointers: Mutex<Pointers>,
/// Number of pending tasks in the queue. This helps prevent unnecessary
@@ -22,13 +22,13 @@ pub(crate) struct Inject<T: 'static> {
}
struct Pointers {
/// True if the queue is closed
/// True if the queue is closed.
is_closed: bool,
/// Linked-list head
/// Linked-list head.
head: Option<NonNull<task::Header>>,
/// Linked-list tail
/// Linked-list tail.
tail: Option<NonNull<task::Header>>,
}
@@ -52,7 +52,7 @@ impl<T: 'static> Inject<T> {
self.len() == 0
}
/// Close the injection queue, returns `true` if the queue is open when the
/// Closes the injection queue, returns `true` if the queue is open when the
/// transition is made.
pub(crate) fn close(&self) -> bool {
let mut p = self.pointers.lock();
@@ -137,7 +137,7 @@ impl<T: 'static> Inject<T> {
self.push_batch_inner(first, prev, counter);
}
/// Insert several tasks that have been linked together into the queue.
/// Inserts several tasks that have been linked together into the queue.
///
/// The provided head and tail may be be the same task. In this case, a
/// single task is inserted.
+5 -5
View File
@@ -78,7 +78,7 @@ impl<S: 'static> OwnedTasks<S> {
}
}
/// Bind the provided task to this OwnedTasks instance. This fails if the
/// Binds the provided task to this OwnedTasks instance. This fails if the
/// OwnedTasks has been closed.
pub(crate) fn bind<T>(
&self,
@@ -110,7 +110,7 @@ impl<S: 'static> OwnedTasks<S> {
}
}
/// Assert that the given task is owned by this OwnedTasks and convert it to
/// Asserts that the given task is owned by this OwnedTasks and convert it to
/// a LocalNotified, giving the thread permission to poll this task.
#[inline]
pub(crate) fn assert_owner(&self, task: Notified<S>) -> LocalNotified<S> {
@@ -124,7 +124,7 @@ impl<S: 'static> OwnedTasks<S> {
}
}
/// Shut down all tasks in the collection. This call also closes the
/// Shuts down all tasks in the collection. This call also closes the
/// collection, preventing new items from being added.
pub(crate) fn close_and_shutdown_all(&self)
where
@@ -213,7 +213,7 @@ impl<S: 'static> LocalOwnedTasks<S> {
}
}
/// Shut down all tasks in the collection. This call also closes the
/// Shuts down all tasks in the collection. This call also closes the
/// collection, preventing new items from being added.
pub(crate) fn close_and_shutdown_all(&self)
where
@@ -241,7 +241,7 @@ impl<S: 'static> LocalOwnedTasks<S> {
unsafe { inner.list.remove(task.header().into()) })
}
/// Assert that the given task is owned by this LocalOwnedTasks and convert
/// Asserts that the given task is owned by this LocalOwnedTasks and convert
/// it to a LocalNotified, giving the thread permission to poll this task.
#[inline]
pub(crate) fn assert_owner(&self, task: Notified<S>) -> LocalNotified<S> {
+6 -6
View File
@@ -173,7 +173,7 @@ use std::marker::PhantomData;
use std::ptr::NonNull;
use std::{fmt, mem};
/// An owned handle to the task, tracked by ref count
/// An owned handle to the task, tracked by ref count.
#[repr(transparent)]
pub(crate) struct Task<S: 'static> {
raw: RawTask,
@@ -211,7 +211,7 @@ pub(crate) struct UnownedTask<S: 'static> {
unsafe impl<S> Send for UnownedTask<S> {}
unsafe impl<S> Sync for UnownedTask<S> {}
/// Task result sent back
/// Task result sent back.
pub(crate) type Result<T> = std::result::Result<T, JoinError>;
pub(crate) trait Schedule: Sync + Sized + 'static {
@@ -260,7 +260,7 @@ cfg_rt! {
(task, notified, join)
}
/// Create a new task with an associated join handle. This method is used
/// Creates a new task with an associated join handle. This method is used
/// only when the task is not going to be stored in an `OwnedTasks` list.
///
/// Currently only blocking tasks use this method.
@@ -327,7 +327,7 @@ cfg_rt_multi_thread! {
}
impl<S: Schedule> Task<S> {
/// Pre-emptively cancel the task as part of the shutdown process.
/// Pre-emptively cancels the task as part of the shutdown process.
pub(crate) fn shutdown(self) {
let raw = self.raw;
mem::forget(self);
@@ -336,7 +336,7 @@ impl<S: Schedule> Task<S> {
}
impl<S: Schedule> LocalNotified<S> {
/// Run the task
/// Runs the task.
pub(crate) fn run(self) {
let raw = self.task.raw;
mem::forget(self);
@@ -420,7 +420,7 @@ impl<S> fmt::Debug for Notified<S> {
/// # Safety
///
/// Tasks are pinned
/// Tasks are pinned.
unsafe impl<S> linked_list::Link for Task<S> {
type Handle = Task<S>;
type Target = Header;
+6 -6
View File
@@ -10,22 +10,22 @@ pub(super) struct RawTask {
}
pub(super) struct Vtable {
/// Poll the future
/// Polls the future.
pub(super) poll: unsafe fn(NonNull<Header>),
/// Deallocate the memory
/// Deallocates the memory.
pub(super) dealloc: unsafe fn(NonNull<Header>),
/// Read the task output, if complete
/// Reads the task output, if complete.
pub(super) try_read_output: unsafe fn(NonNull<Header>, *mut (), &Waker),
/// The join handle has been dropped
/// The join handle has been dropped.
pub(super) drop_join_handle_slow: unsafe fn(NonNull<Header>),
/// The task is remotely aborted
/// The task is remotely aborted.
pub(super) remote_abort: unsafe fn(NonNull<Header>),
/// Scheduler is being shutdown
/// Scheduler is being shutdown.
pub(super) shutdown: unsafe fn(NonNull<Header>),
}
+18 -18
View File
@@ -8,7 +8,7 @@ pub(super) struct State {
val: AtomicUsize,
}
/// Current state value
/// Current state value.
#[derive(Copy, Clone)]
pub(super) struct Snapshot(usize);
@@ -19,20 +19,20 @@ const RUNNING: usize = 0b0001;
/// The task is complete.
///
/// Once this bit is set, it is never unset
/// Once this bit is set, it is never unset.
const COMPLETE: usize = 0b0010;
/// Extracts the task's lifecycle value from the state
/// Extracts the task's lifecycle value from the state.
const LIFECYCLE_MASK: usize = 0b11;
/// Flag tracking if the task has been pushed into a run queue.
const NOTIFIED: usize = 0b100;
/// The join handle is still around
/// The join handle is still around.
#[allow(clippy::unusual_byte_groupings)] // https://github.com/rust-lang/rust-clippy/issues/6556
const JOIN_INTEREST: usize = 0b1_000;
/// A join handle waker has been set
/// A join handle waker has been set.
#[allow(clippy::unusual_byte_groupings)] // https://github.com/rust-lang/rust-clippy/issues/6556
const JOIN_WAKER: usize = 0b10_000;
@@ -40,19 +40,19 @@ const JOIN_WAKER: usize = 0b10_000;
#[allow(clippy::unusual_byte_groupings)] // https://github.com/rust-lang/rust-clippy/issues/6556
const CANCELLED: usize = 0b100_000;
/// All bits
/// All bits.
const STATE_MASK: usize = LIFECYCLE_MASK | NOTIFIED | JOIN_INTEREST | JOIN_WAKER | CANCELLED;
/// Bits used by the ref count portion of the state.
const REF_COUNT_MASK: usize = !STATE_MASK;
/// Number of positions to shift the ref count
/// Number of positions to shift the ref count.
const REF_COUNT_SHIFT: usize = REF_COUNT_MASK.count_zeros() as usize;
/// One ref count
/// One ref count.
const REF_ONE: usize = 1 << REF_COUNT_SHIFT;
/// State a task is initialized with
/// State a task is initialized with.
///
/// A task is initialized with three references:
///
@@ -96,7 +96,7 @@ pub(super) enum TransitionToNotifiedByRef {
/// All transitions are performed via RMW operations. This establishes an
/// unambiguous modification order.
impl State {
/// Return a task's initial state
/// Returns a task's initial state.
pub(super) fn new() -> State {
// The raw task returned by this method has a ref-count of three. See
// the comment on INITIAL_STATE for more.
@@ -110,7 +110,7 @@ impl State {
Snapshot(self.val.load(Acquire))
}
/// Attempt to transition the lifecycle to `Running`. This sets the
/// Attempts to transition the lifecycle to `Running`. This sets the
/// notified bit to false so notifications during the poll can be detected.
pub(super) fn transition_to_running(&self) -> TransitionToRunning {
self.fetch_update_action(|mut next| {
@@ -190,7 +190,7 @@ impl State {
Snapshot(prev.0 ^ DELTA)
}
/// Transition from `Complete` -> `Terminal`, decrementing the reference
/// Transitions from `Complete` -> `Terminal`, decrementing the reference
/// count the specified number of times.
///
/// Returns true if the task should be deallocated.
@@ -270,10 +270,10 @@ impl State {
})
}
/// Set the cancelled bit and transition the state to `NOTIFIED` if idle.
/// Sets the cancelled bit and transitions the state to `NOTIFIED` if idle.
///
/// Returns `true` if the task needs to be submitted to the pool for
/// execution
/// execution.
pub(super) fn transition_to_notified_and_cancel(&self) -> bool {
self.fetch_update_action(|mut snapshot| {
if snapshot.is_cancelled() || snapshot.is_complete() {
@@ -306,7 +306,7 @@ impl State {
})
}
/// Set the `CANCELLED` bit and attempt to transition to `Running`.
/// Sets the `CANCELLED` bit and attempts to transition to `Running`.
///
/// Returns `true` if the transition to `Running` succeeded.
pub(super) fn transition_to_shutdown(&self) -> bool {
@@ -330,7 +330,7 @@ impl State {
}
/// Optimistically tries to swap the state assuming the join handle is
/// __immediately__ dropped on spawn
/// __immediately__ dropped on spawn.
pub(super) fn drop_join_handle_fast(&self) -> Result<(), ()> {
use std::sync::atomic::Ordering::Relaxed;
@@ -352,7 +352,7 @@ impl State {
.map_err(|_| ())
}
/// Try to unset the JOIN_INTEREST flag.
/// Tries to unset the JOIN_INTEREST flag.
///
/// Returns `Ok` if the operation happens before the task transitions to a
/// completed state, `Err` otherwise.
@@ -371,7 +371,7 @@ impl State {
})
}
/// Set the `JOIN_WAKER` bit.
/// Sets the `JOIN_WAKER` bit.
///
/// Returns `Ok` if the bit is set, `Err` otherwise. This operation fails if
/// the task has completed.
@@ -63,6 +63,45 @@ fn block_on_num_polls() {
});
}
#[test]
fn assert_no_unnecessary_polls() {
loom::model(|| {
// // After we poll outer future, woken should reset to false
let rt = Builder::new_current_thread().build().unwrap();
let (tx, rx) = oneshot::channel();
let pending_cnt = Arc::new(AtomicUsize::new(0));
rt.spawn(async move {
for _ in 0..24 {
task::yield_now().await;
}
tx.send(()).unwrap();
});
let pending_cnt_clone = pending_cnt.clone();
rt.block_on(async move {
// use task::yield_now() to ensure woken set to true
// ResetFuture will be polled at most once
// Here comes two cases
// 1. recv no message from channel, ResetFuture will be polled
// but get Pending and we record ResetFuture.pending_cnt ++.
// Then when message arrive, ResetFuture returns Ready. So we
// expect ResetFuture.pending_cnt = 1
// 2. recv message from channel, ResetFuture returns Ready immediately.
// We expect ResetFuture.pending_cnt = 0
task::yield_now().await;
ResetFuture {
rx,
pending_cnt: pending_cnt_clone,
}
.await;
});
let pending_cnt = pending_cnt.load(Acquire);
assert!(pending_cnt <= 1);
});
}
struct BlockedFuture {
rx: Receiver<()>,
num_polls: Arc<AtomicUsize>,
@@ -80,3 +119,22 @@ impl Future for BlockedFuture {
}
}
}
struct ResetFuture {
rx: Receiver<()>,
pending_cnt: Arc<AtomicUsize>,
}
impl Future for ResetFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.rx).poll(cx) {
Poll::Pending => {
self.pending_cnt.fetch_add(1, Release);
Poll::Pending
}
_ => Poll::Ready(()),
}
}
}
+1 -1
View File
@@ -126,7 +126,7 @@ impl Idle {
}
}
/// Returns `true` if `worker_id` is contained in the sleep set
/// Returns `true` if `worker_id` is contained in the sleep set.
pub(super) fn is_parked(&self, worker_id: usize) -> bool {
let sleepers = self.sleepers.lock();
sleepers.contains(&worker_id)
+1 -1
View File
@@ -24,7 +24,7 @@ pub(crate) struct ThreadPool {
spawner: Spawner,
}
/// Submit futures to the associated thread pool for execution.
/// Submits futures to the associated thread pool for execution.
///
/// A `Spawner` instance is a handle to a single thread pool that allows the owner
/// of the handle to spawn futures onto the thread pool.

Some files were not shown because too many files have changed in this diff Show More