Skip to content

Commit

Permalink
Implement blocking output
Browse files Browse the repository at this point in the history
This allows decoupling `Command::spawn` and `Command::output`. This is
useful for targets which do support launching programs in blocking mode
but do not support multitasking (Eg: UEFI).

This was originally conceived when working on #100316

Signed-off-by: Ayush Singh <ayushsingh1325@gmail.com>
  • Loading branch information
Ayush1325 committed Dec 8, 2022
1 parent 5479fe5 commit 1ba9790
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 5 deletions.
6 changes: 2 additions & 4 deletions library/std/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,10 +911,8 @@ impl Command {
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn output(&mut self) -> io::Result<Output> {
self.inner
.spawn(imp::Stdio::MakePipe, false)
.map(Child::from_inner)
.and_then(|p| p.wait_with_output())
let (status, stdout, stderr) = self.inner.output()?;
Ok(Output { status: ExitStatus(status), stdout, stderr })
}

/// Executes a command as a child process, waiting for it to finish and
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/sys/unix/process/process_fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ impl Command {
Ok((Process { handle: Handle::new(process_handle) }, ours))
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}

pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul() {
return io::const_io_error!(
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/sys/unix/process/process_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ impl Command {
}
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}

// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
#[cfg(not(target_os = "linux"))]
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/sys/unix/process/process_unsupported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ impl Command {
unsupported()
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}

pub fn exec(&mut self, _default: Stdio) -> io::Error {
unsupported_err()
}
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/sys/unix/process/process_vxworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ impl Command {
}
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}

pub fn exec(&mut self, default: Stdio) -> io::Error {
let ret = Command::spawn(self, default, false);
match ret {
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/sys/unsupported/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ impl Command {
) -> io::Result<(Process, StdioPipes)> {
unsupported()
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
unsupported()
}
}

impl From<AnonPipe> for Stdio {
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/sys/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ impl Command {
))
}
}

pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
crate::sys_common::process::wait_with_output(proc, pipes)
}
}

impl fmt::Debug for Command {
Expand Down
31 changes: 30 additions & 1 deletion library/std/src/sys_common/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use crate::collections::BTreeMap;
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::sys::process::EnvKey;
use crate::io;
use crate::sys::pipe::read2;
use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};

// Stores a set of changes to an environment
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -117,3 +119,30 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
self.iter.is_empty()
}
}

pub fn wait_with_output(
mut process: Process,
mut pipes: StdioPipes,
) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
drop(pipes.stdin.take());

let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
match (pipes.stdout.take(), pipes.stderr.take()) {
(None, None) => {}
(Some(out), None) => {
let res = out.read_to_end(&mut stdout);
res.unwrap();
}
(None, Some(err)) => {
let res = err.read_to_end(&mut stderr);
res.unwrap();
}
(Some(out), Some(err)) => {
let res = read2(out, &mut stdout, err, &mut stderr);
res.unwrap();
}
}

let status = process.wait()?;
Ok((status, stdout, stderr))
}

0 comments on commit 1ba9790

Please sign in to comment.