Skip to content

Commit 6afa32a

Browse files
committed
std: Don't always create stdin for children
For example if `Command::output` or `Command::status` is used then stdin is just immediately closed. Add an option for this so as an optimization we can avoid creating pipes entirely. This should help reduce the number of active file descriptors when spawning processes on Unix and the number of active handles on Windows.
1 parent d46c99a commit 6afa32a

File tree

3 files changed

+16
-10
lines changed

3 files changed

+16
-10
lines changed

src/libstd/process.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ impl Command {
295295
/// By default, stdin, stdout and stderr are inherited from the parent.
296296
#[stable(feature = "process", since = "1.0.0")]
297297
pub fn spawn(&mut self) -> io::Result<Child> {
298-
self.inner.spawn(imp::Stdio::Inherit).map(Child::from_inner)
298+
self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner)
299299
}
300300

301301
/// Executes the command as a child process, waiting for it to finish and
@@ -318,7 +318,7 @@ impl Command {
318318
/// ```
319319
#[stable(feature = "process", since = "1.0.0")]
320320
pub fn output(&mut self) -> io::Result<Output> {
321-
self.inner.spawn(imp::Stdio::MakePipe).map(Child::from_inner)
321+
self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner)
322322
.and_then(|p| p.wait_with_output())
323323
}
324324

@@ -340,7 +340,8 @@ impl Command {
340340
/// ```
341341
#[stable(feature = "process", since = "1.0.0")]
342342
pub fn status(&mut self) -> io::Result<ExitStatus> {
343-
self.spawn().and_then(|mut p| p.wait())
343+
self.inner.spawn(imp::Stdio::Inherit, false).map(Child::from_inner)
344+
.and_then(|mut p| p.wait())
344345
}
345346
}
346347

src/libstd/sys/unix/process.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl Command {
216216
self.stderr = Some(stderr);
217217
}
218218

219-
pub fn spawn(&mut self, default: Stdio)
219+
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
220220
-> io::Result<(Process, StdioPipes)> {
221221
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
222222

@@ -225,7 +225,7 @@ impl Command {
225225
"nul byte found in provided data"));
226226
}
227227

228-
let (ours, theirs) = try!(self.setup_io(default));
228+
let (ours, theirs) = try!(self.setup_io(default, needs_stdin));
229229
let (input, output) = try!(sys::pipe::anon_pipe());
230230

231231
let pid = unsafe {
@@ -298,7 +298,7 @@ impl Command {
298298
"nul byte found in provided data")
299299
}
300300

301-
match self.setup_io(default) {
301+
match self.setup_io(default, true) {
302302
Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
303303
Err(e) => e,
304304
}
@@ -408,8 +408,11 @@ impl Command {
408408
}
409409

410410

411-
fn setup_io(&self, default: Stdio) -> io::Result<(StdioPipes, ChildPipes)> {
412-
let stdin = self.stdin.as_ref().unwrap_or(&default);
411+
fn setup_io(&self, default: Stdio, needs_stdin: bool)
412+
-> io::Result<(StdioPipes, ChildPipes)> {
413+
let null = Stdio::Null;
414+
let default_stdin = if needs_stdin {&default} else {&null};
415+
let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
413416
let stdout = self.stdout.as_ref().unwrap_or(&default);
414417
let stderr = self.stderr.as_ref().unwrap_or(&default);
415418
let (their_stdin, our_stdin) = try!(stdin.to_child_stdio(true));

src/libstd/sys/windows/process.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ impl Command {
123123
self.stderr = Some(stderr);
124124
}
125125

126-
pub fn spawn(&mut self, default: Stdio)
126+
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
127127
-> io::Result<(Process, StdioPipes)> {
128128
// To have the spawning semantics of unix/windows stay the same, we need
129129
// to read the *child's* PATH if one is provided. See #15149 for more
@@ -181,7 +181,9 @@ impl Command {
181181
stdout: None,
182182
stderr: None,
183183
};
184-
let stdin = self.stdin.as_ref().unwrap_or(&default);
184+
let null = Stdio::Null;
185+
let default_stdin = if needs_stdin {&default} else {&null};
186+
let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
185187
let stdout = self.stdout.as_ref().unwrap_or(&default);
186188
let stderr = self.stderr.as_ref().unwrap_or(&default);
187189
let stdin = try!(stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin));

0 commit comments

Comments
 (0)