Skip to content

Commit d15db1d

Browse files
committed
std: Push process stdio setup in std::sys
Most of this is platform-specific anyway, and we generally have to jump through fewer hoops to do the equivalent operation on Windows. One benefit for Windows today is that this new structure avoids an extra `DuplicateHandle` when creating pipes. For Unix, however, the behavior should be the same. Note that this is just a pure refactoring, no functionality was added or removed.
1 parent 18f9a79 commit d15db1d

File tree

7 files changed

+440
-367
lines changed

7 files changed

+440
-367
lines changed

src/libstd/process.rs

Lines changed: 44 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use fmt;
2020
use io;
2121
use path::Path;
2222
use str;
23-
use sys::pipe::{self, AnonPipe};
23+
use sys::pipe::AnonPipe;
2424
use sys::process as imp;
2525
use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
2626
use thread::{self, JoinHandle};
@@ -77,6 +77,17 @@ impl AsInner<imp::Process> for Child {
7777
fn as_inner(&self) -> &imp::Process { &self.handle }
7878
}
7979

80+
impl FromInner<(imp::Process, imp::StdioPipes)> for Child {
81+
fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child {
82+
Child {
83+
handle: handle,
84+
stdin: io.stdin.map(ChildStdin::from_inner),
85+
stdout: io.stdout.map(ChildStdout::from_inner),
86+
stderr: io.stderr.map(ChildStderr::from_inner),
87+
}
88+
}
89+
}
90+
8091
impl IntoInner<imp::Process> for Child {
8192
fn into_inner(self) -> imp::Process { self.handle }
8293
}
@@ -106,6 +117,12 @@ impl IntoInner<AnonPipe> for ChildStdin {
106117
fn into_inner(self) -> AnonPipe { self.inner }
107118
}
108119

120+
impl FromInner<AnonPipe> for ChildStdin {
121+
fn from_inner(pipe: AnonPipe) -> ChildStdin {
122+
ChildStdin { inner: pipe }
123+
}
124+
}
125+
109126
/// A handle to a child process's stdout
110127
#[stable(feature = "process", since = "1.0.0")]
111128
pub struct ChildStdout {
@@ -127,6 +144,12 @@ impl IntoInner<AnonPipe> for ChildStdout {
127144
fn into_inner(self) -> AnonPipe { self.inner }
128145
}
129146

147+
impl FromInner<AnonPipe> for ChildStdout {
148+
fn from_inner(pipe: AnonPipe) -> ChildStdout {
149+
ChildStdout { inner: pipe }
150+
}
151+
}
152+
130153
/// A handle to a child process's stderr
131154
#[stable(feature = "process", since = "1.0.0")]
132155
pub struct ChildStderr {
@@ -148,6 +171,12 @@ impl IntoInner<AnonPipe> for ChildStderr {
148171
fn into_inner(self) -> AnonPipe { self.inner }
149172
}
150173

174+
impl FromInner<AnonPipe> for ChildStderr {
175+
fn from_inner(pipe: AnonPipe) -> ChildStderr {
176+
ChildStderr { inner: pipe }
177+
}
178+
}
179+
151180
/// The `Command` type acts as a process builder, providing fine-grained control
152181
/// over how a new process should be spawned. A default configuration can be
153182
/// generated using `Command::new(program)`, where `program` gives a path to the
@@ -167,11 +196,6 @@ impl IntoInner<AnonPipe> for ChildStderr {
167196
#[stable(feature = "process", since = "1.0.0")]
168197
pub struct Command {
169198
inner: imp::Command,
170-
171-
// Details explained in the builder methods
172-
stdin: Option<Stdio>,
173-
stdout: Option<Stdio>,
174-
stderr: Option<Stdio>,
175199
}
176200

177201
impl Command {
@@ -187,12 +211,7 @@ impl Command {
187211
/// otherwise configure the process.
188212
#[stable(feature = "process", since = "1.0.0")]
189213
pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
190-
Command {
191-
inner: imp::Command::new(program.as_ref()),
192-
stdin: None,
193-
stdout: None,
194-
stderr: None,
195-
}
214+
Command { inner: imp::Command::new(program.as_ref()) }
196215
}
197216

198217
/// Add an argument to pass to the program.
@@ -247,56 +266,30 @@ impl Command {
247266
/// Configuration for the child process's stdin handle (file descriptor 0).
248267
#[stable(feature = "process", since = "1.0.0")]
249268
pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
250-
self.stdin = Some(cfg);
269+
self.inner.stdin(cfg.0);
251270
self
252271
}
253272

254273
/// Configuration for the child process's stdout handle (file descriptor 1).
255274
#[stable(feature = "process", since = "1.0.0")]
256275
pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
257-
self.stdout = Some(cfg);
276+
self.inner.stdout(cfg.0);
258277
self
259278
}
260279

261280
/// Configuration for the child process's stderr handle (file descriptor 2).
262281
#[stable(feature = "process", since = "1.0.0")]
263282
pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
264-
self.stderr = Some(cfg);
283+
self.inner.stderr(cfg.0);
265284
self
266285
}
267286

268-
fn spawn_inner(&mut self, default_io: StdioImp) -> io::Result<Child> {
269-
let default_io = Stdio(default_io);
270-
271-
// See comment on `setup_io` for what `_drop_later` is.
272-
let (their_stdin, our_stdin, _drop_later) = try!(
273-
setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
274-
);
275-
let (their_stdout, our_stdout, _drop_later) = try!(
276-
setup_io(self.stdout.as_ref().unwrap_or(&default_io), false)
277-
);
278-
let (their_stderr, our_stderr, _drop_later) = try!(
279-
setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
280-
);
281-
282-
match imp::Process::spawn(&mut self.inner, their_stdin, their_stdout,
283-
their_stderr) {
284-
Err(e) => Err(e),
285-
Ok(handle) => Ok(Child {
286-
handle: handle,
287-
stdin: our_stdin.map(|fd| ChildStdin { inner: fd }),
288-
stdout: our_stdout.map(|fd| ChildStdout { inner: fd }),
289-
stderr: our_stderr.map(|fd| ChildStderr { inner: fd }),
290-
})
291-
}
292-
}
293-
294287
/// Executes the command as a child process, returning a handle to it.
295288
///
296289
/// By default, stdin, stdout and stderr are inherited from the parent.
297290
#[stable(feature = "process", since = "1.0.0")]
298291
pub fn spawn(&mut self) -> io::Result<Child> {
299-
self.spawn_inner(StdioImp::Inherit)
292+
self.inner.spawn(imp::Stdio::Inherit).map(Child::from_inner)
300293
}
301294

302295
/// Executes the command as a child process, waiting for it to finish and
@@ -319,7 +312,8 @@ impl Command {
319312
/// ```
320313
#[stable(feature = "process", since = "1.0.0")]
321314
pub fn output(&mut self) -> io::Result<Output> {
322-
self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output())
315+
self.inner.spawn(imp::Stdio::MakePipe).map(Child::from_inner)
316+
.and_then(|p| p.wait_with_output())
323317
}
324318

325319
/// Executes a command as a child process, waiting for it to finish and
@@ -362,33 +356,6 @@ impl AsInnerMut<imp::Command> for Command {
362356
fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
363357
}
364358

365-
// Takes a `Stdio` configuration (this module) and whether the to-be-owned
366-
// handle will be readable.
367-
//
368-
// Returns a triple of (stdio to spawn with, stdio to store, stdio to drop). The
369-
// stdio to spawn with is passed down to the `sys` module and indicates how the
370-
// stdio stream should be set up. The "stdio to store" is an object which
371-
// should be returned in the `Child` that makes its way out. The "stdio to drop"
372-
// represents the raw value of "stdio to spawn with", but is the owned variant
373-
// for it. This needs to be dropped after the child spawns
374-
fn setup_io(io: &Stdio, readable: bool)
375-
-> io::Result<(imp::Stdio, Option<AnonPipe>, Option<AnonPipe>)>
376-
{
377-
Ok(match io.0 {
378-
StdioImp::MakePipe => {
379-
let (reader, writer) = try!(pipe::anon_pipe());
380-
if readable {
381-
(imp::Stdio::Raw(reader.raw()), Some(writer), Some(reader))
382-
} else {
383-
(imp::Stdio::Raw(writer.raw()), Some(reader), Some(writer))
384-
}
385-
}
386-
StdioImp::Raw(ref owned) => (imp::Stdio::Raw(owned.raw()), None, None),
387-
StdioImp::Inherit => (imp::Stdio::Inherit, None, None),
388-
StdioImp::Null => (imp::Stdio::Null, None, None),
389-
})
390-
}
391-
392359
/// The output of a finished process.
393360
#[derive(PartialEq, Eq, Clone)]
394361
#[stable(feature = "process", since = "1.0.0")]
@@ -432,34 +399,26 @@ impl fmt::Debug for Output {
432399

433400
/// Describes what to do with a standard I/O stream for a child process.
434401
#[stable(feature = "process", since = "1.0.0")]
435-
pub struct Stdio(StdioImp);
436-
437-
// The internal enum for stdio setup; see below for descriptions.
438-
enum StdioImp {
439-
MakePipe,
440-
Raw(imp::RawStdio),
441-
Inherit,
442-
Null,
443-
}
402+
pub struct Stdio(imp::Stdio);
444403

445404
impl Stdio {
446405
/// A new pipe should be arranged to connect the parent and child processes.
447406
#[stable(feature = "process", since = "1.0.0")]
448-
pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) }
407+
pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) }
449408

450409
/// The child inherits from the corresponding parent descriptor.
451410
#[stable(feature = "process", since = "1.0.0")]
452-
pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) }
411+
pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
453412

454413
/// This stream will be ignored. This is the equivalent of attaching the
455414
/// stream to `/dev/null`
456415
#[stable(feature = "process", since = "1.0.0")]
457-
pub fn null() -> Stdio { Stdio(StdioImp::Null) }
416+
pub fn null() -> Stdio { Stdio(imp::Stdio::Null) }
458417
}
459418

460-
impl FromInner<imp::RawStdio> for Stdio {
461-
fn from_inner(inner: imp::RawStdio) -> Stdio {
462-
Stdio(StdioImp::Raw(inner))
419+
impl FromInner<imp::Stdio> for Stdio {
420+
fn from_inner(inner: imp::Stdio) -> Stdio {
421+
Stdio(inner)
463422
}
464423
}
465424

src/libstd/sys/unix/ext/process.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ impl ExitStatusExt for process::ExitStatus {
120120
#[stable(feature = "process_extensions", since = "1.2.0")]
121121
impl FromRawFd for process::Stdio {
122122
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
123-
process::Stdio::from_inner(sys::fd::FileDesc::new(fd))
123+
let fd = sys::fd::FileDesc::new(fd);
124+
let io = sys::process::Stdio::Fd(fd);
125+
process::Stdio::from_inner(io)
124126
}
125127
}
126128

src/libstd/sys/unix/pipe.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ impl AnonPipe {
6161
self.0.write(buf)
6262
}
6363

64-
pub fn raw(&self) -> libc::c_int { self.0.raw() }
6564
pub fn fd(&self) -> &FileDesc { &self.0 }
6665
pub fn into_fd(self) -> FileDesc { self.0 }
6766
}

0 commit comments

Comments
 (0)