-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
Description
No discussions here please. Use this Zulip topic instead.
Feature gate: #![feature(on_broken_pipe)]
This is a tracking issue for the externally implementable item std::io::on_broken_pipe() -> std::io::OnBrokenPipe that allows programs to affect the SIGPIPE setup code that runs before fn main() is invoked.
Supersedes: #97889 (which will be closed once we have a bare-bones implementation in place.)
Usage
A Rust program that writes a sizeable amount of data to stdout with println!() will panic if its output is piped to a short-lived program:
fn main() {
loop {
println!("hello world");
}
}% ./main | head
hello world
thread 'main' (3260965) panicked at library/std/src/io/stdio.rs:1165:9:
failed printing to stdout: Broken pipe (os error 32)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtraceThis is because SIGPIPE is changed to SIG_IGN before fn main() is invoked. To prevent panicking, a program can override the new externally implementable item to request that SIGPIPE is not changed before fn main() is invoked. Its disposition will remain SIG_DFL and the program will be killed without error when the pipe is closed:
#![feature(on_broken_pipe)]
#![feature(extern_item_impls)]
/// The standard library asks this function how to setup `SIGPIPE` before `fn main()` is invoked.
/// Here we tell it to inherit `SIGPIPE` from the parent process, which in practice means `SIG_DFL`.
/// This implememtation can also come from an external crate that we link with.
#[std::io::on_broken_pipe]
fn inherit_on_broken_pipe() -> std::io::OnBrokenPipe {
std::io::OnBrokenPipe::Inherit
}
fn main() {
loop {
println!("hello world");
}
}% ./main | head
hello worldPublic API
/// How to change SIGPIPE disposition before `fn main()` is invoked. This lives
/// in `std::io` and is an Externally Implementable Item (eii) that can be
/// overidden by crates even though it is called by std itself.
pub fn on_broken_pipe() -> std::io::OnBrokenPipe {
std::io::OnBrokenPipe::Default
}
/// Specifies what [`ErrorKind::BrokenPipe`] behavior a program should have. In
/// practice this affects the `SIGPIPE` setup code that runs before `fn main()`.
/// Currently only relevant to the `unix` family of operating systems.
#[non_exhaustive] // We want to be able to add more variants later.
pub enum OnBrokenPipe {
/// Set `SIGPIPE` to `SIG_IGN` so that pipe I/O problems are reported as
/// [`ErrorKind::BrokenPipe`] errors. Reset `SIGPIPE` to `SIG_DFL` before
/// child `exec()`.
///
/// Both of these behaviors have been the default since Rust 1.0.
BackwardsCompatible,
/// Set `SIGPIPE` to `SIG_IGN` so that pipe I/O problems kills the process.
/// Don't touch `SIGPIPE` before child `exec()`.
///
/// This is mainly useful when you want programs to terminate when their
/// output is piped to short-lived programs like `head`.
Kill,
/// Set `SIGPIPE` to `SIG_DFL` so that pipe I/O problems are reported as
/// [`ErrorKind::BrokenPipe`] errors. Don't touch `SIGPIPE` before child
/// `exec()`.
Error,
/// Never touch `SIGPIPE`, including before child `exec()`.
/// `SIGPIPE` disposition is always inherited from the parent process.
/// This typically means that programs behave as with [`Self::Kill`].
Inherit,
}Steps
- Basic Implementation
- Fix Hundreds of
missing stability attributeerrors with trivial Externally Implementable Item (eii) function inlibrary/std#150514 - Implement the externally implementable item
std::io::on_broken_pipe() -> std::io::OnBrokenPipe. - Somehow handle that eii don't work yet on e.g. mingw. Zulip Discussion#t-libs > on_broken_pipe eii to fix SIGPIPE @ 💬.
- Remove old
-Zon-broken-pipe=...code. - Make
#![feature(extern_item_impls)]implicit from#![feature(on_broken_pipe)] - Remove
sigpipe: u8fromfn lang_start()instd.
- Fix Hundreds of
- Leveled Up Implementation
- Add proper miri support. See Replace
-Zon-broken-pipe=...with Externally Implementable Item#[std::io::on_broken_pipe]#150591 (comment).
- Add proper miri support. See Replace
- Carefully go through the discussion in the old tracking issue Tracking Issue for
unix_sigpipe#97889 to make sure we cover all aspects of this problem. - Adjust documentation in relevant places
- Final comment period (FCP)1
- Stabilization PR
(Remember to update the S-tracking-* label when checking boxes.)
History
This feature will solve:
This feature was originally implemented as an attribute #[unix_sigpipe = "..."]. It was later changed to a compiler flag -Zon-broken-pipe=.... It is now implemented as an externally implementable item std::io::on_broken_pipe() -> std::io::OnBrokenPipe.
Unresolved Questions
- Should we stabilize
OnBrokenPipe::KillandErroror isInheritandDefaultsufficient? - Can we stabilize
#[feature(on_broken_pipe)]without stabilizing#![feature(extern_item_impls)]?
Unresolved Questions That Does Not Block Stabilisation
Because these questions can be resolved after stabilization.
- What is the long-term plan with regards to changing the default behaviour with regards to ignoring
SIGPIPE, if we want to do it at all?
Resolved Questions
- Can and should we alter the
BrokenPipeerror message and make it suggest to use the new attribute? Answer: No, because that would mean we would end up giving developer advice to users that can't act on the advice. - Can we use
MSG_NOSIGNALwithsend()etc instead of settingSIGPIPEglobally? Answer: No, because there is no equivalent forwrite(), and it would incur an extra syscall for each write-operation, which is likely to have significant performance drawbacks.