Description
Description
The docs for TcpStream::shutdown
currently guarantee that a shutdown with Shutdown::Read
must wake up pending operations immediately:
This function will cause all pending and future I/O on the specified portions to return immediately with an appropriate value (see the documentation of Shutdown).
The docs for Shutdown::Read
explicitly says that currently blocked reads must return:
However, that is currently not the case on *-pc-windows-*
platforms. Instead, a currently blocked read will stay blocked forever when shutdown is called with Shutdown::Read
in a different thread. The same also happens with Shutdown::Both
.
This is causing the close_read_wakes_up
test to fail spuriously due to a race condition, for example in #121523 (comment) and #120543 (comment). The test only passes if the shutdown
happens before the read
.
Repro
I tried this code:
use std::io::Read;
use std::net::{Ipv6Addr, Shutdown, TcpListener, TcpStream};
use std::thread;
use std::time::Duration;
fn main() {
let listener = TcpListener::bind((Ipv6Addr::LOCALHOST, 0)).unwrap();
let listener_addr = listener.local_addr().unwrap();
let mut serverbound_stream = None;
thread::scope(|scope| {
// 1. `accept` and `connect` concurrently
let _clientbound_stream = scope.spawn(|| {
let (clientbound_stream, _) = listener.accept().unwrap();
clientbound_stream
});
let serverbound_stream =
serverbound_stream.insert(TcpStream::connect(listener_addr).unwrap());
// 3. shutdown read during blocking read
scope.spawn(|| {
thread::sleep(Duration::from_secs(1)); // just to be sure
serverbound_stream.shutdown(Shutdown::Read).unwrap();
});
// 2. blocking read
let count = (&*serverbound_stream).read(&mut [0]).unwrap();
assert_eq!(count, 0);
});
}
I expected to see this happen: The .shutdown(Shutdown::Read)
makes the blocking read return immediately with Ok(0)
.
Instead, this happened: The blocking read does not return, making the program hang indefinitely.
Meta
rustc --version --verbose
:
rustc 1.78.0-nightly (381d69953 2024-02-24)
binary: rustc
commit-hash: 381d69953bb7c3390cec0fee200f24529cb6320f
commit-date: 2024-02-24
host: x86_64-unknown-linux-gnu
release: 1.78.0-nightly
LLVM version: 18.1.0
Tested on these platforms:
x86_64-pc-windows-msvc
with Microsoft Windows Server 2019 (GitHub CI)x86_64-pc-windows-gnu
with wine 9.1 on Linux
Related
- std: Ignore close_read_wakes_up on Windows #38867 disabled the test due to "We don't document this as a guarantee for
shutdown
", except that we do and also already did when that PR was opened. - Enable
close_read_wakes_up
test on Windows #94714 enabled the test again as "works on my machine".