From e638d4d33b93735ade597cf8d600e05a80c506c3 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Fri, 16 May 2025 20:05:18 -0700 Subject: [PATCH] update the std::io::pipe() example to comment deadlocks The previous version of the example wasn't a deadlock, but only because the Command object was a temporary. That's quite subtle, and I think it's better to call out the potential deadlock explicitly. --- content/Rust-1.87.0/index.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/content/Rust-1.87.0/index.md b/content/Rust-1.87.0/index.md index f8aee6878..d66992133 100644 --- a/content/Rust-1.87.0/index.md +++ b/content/Rust-1.87.0/index.md @@ -51,20 +51,25 @@ or platform-specific functions. use std::process::Command; use std::io::Read; -let (mut recv, send) = std::io::pipe()?; +let (mut reader, writer) = std::io::pipe()?; -let mut command = Command::new("path/to/bin") - // Both stdout and stderr will write to the same pipe, combining the two. - .stdout(send.try_clone()?) - .stderr(send) - .spawn()?; +let mut command = Command::new("path/to/bin"); +// Both stdout and stderr will write to the same pipe, combining the two. +command.stdout(writer.try_clone()?); +command.stderr(writer); +let mut child = command.spawn()?; + +// .read_to_end() will block until all pipe writers are closed, but the Command +// object is still holding two of them. Dropping it closes those writers and +// prevents a deadlock. +drop(command); let mut output = Vec::new(); -recv.read_to_end(&mut output)?; +reader.read_to_end(&mut output)?; // It's important that we read from the pipe before the process exits, to avoid // filling the OS buffers if the program emits too much output. -assert!(command.wait()?.success()); +assert!(child.wait()?.success()); ``` ### Safe architecture intrinsics