Skip to content

Commit f6341a8

Browse files
committed
Auto merge of #26159 - alexcrichton:tweak-process-lowering-raising, r=brson
* Slate these features to be stable in 1.2 instead of 1.1 (not being backported) * Have the `FromRawFd` implementations follow the contract of the `FromRawFd` trait by taking ownership of the primitive specified. * Refactor the implementations slightly to remove the `unreachable!` blocks as well as separating the stdio representation of `std::process` from `std::sys::process`. cc #25494
2 parents cf0edd0 + 56a5ff2 commit f6341a8

File tree

8 files changed

+60
-101
lines changed

8 files changed

+60
-101
lines changed

src/libstd/process.rs

+28-13
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,15 @@ impl Command {
243243

244244
fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> {
245245
let default_io = Stdio(default_io);
246-
let (their_stdin, our_stdin) = try!(
246+
247+
// See comment on `setup_io` for what `_drop_later` is.
248+
let (their_stdin, our_stdin, _drop_later) = try!(
247249
setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
248250
);
249-
let (their_stdout, our_stdout) = try!(
251+
let (their_stdout, our_stdout, _drop_later) = try!(
250252
setup_io(self.stdout.as_ref().unwrap_or(&default_io), false)
251253
);
252-
let (their_stderr, our_stderr) = try!(
254+
let (their_stderr, our_stderr, _drop_later) = try!(
253255
setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
254256
);
255257

@@ -271,7 +273,7 @@ impl Command {
271273
/// By default, stdin, stdout and stderr are inherited from the parent.
272274
#[stable(feature = "process", since = "1.0.0")]
273275
pub fn spawn(&mut self) -> io::Result<Child> {
274-
self.spawn_inner(StdioImp::Raw(imp::Stdio::Inherit))
276+
self.spawn_inner(StdioImp::Inherit)
275277
}
276278

277279
/// Executes the command as a child process, waiting for it to finish and
@@ -341,19 +343,30 @@ impl AsInnerMut<imp::Command> for Command {
341343
fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
342344
}
343345

346+
// Takes a `Stdio` configuration (this module) and whether the to-be-owned
347+
// handle will be readable.
348+
//
349+
// Returns a triple of (stdio to spawn with, stdio to store, stdio to drop). The
350+
// stdio to spawn with is passed down to the `sys` module and indicates how the
351+
// stdio stream should be set up. The "stdio to store" is an object which
352+
// should be returned in the `Child` that makes its way out. The "stdio to drop"
353+
// represents the raw value of "stdio to spawn with", but is the owned variant
354+
// for it. This needs to be dropped after the child spawns
344355
fn setup_io(io: &Stdio, readable: bool)
345-
-> io::Result<(imp::Stdio, Option<AnonPipe>)>
356+
-> io::Result<(imp::Stdio, Option<AnonPipe>, Option<AnonPipe>)>
346357
{
347358
Ok(match io.0 {
348359
StdioImp::MakePipe => {
349360
let (reader, writer) = try!(pipe::anon_pipe());
350361
if readable {
351-
(imp::Stdio::Piped(reader), Some(writer))
362+
(imp::Stdio::Raw(reader.raw()), Some(writer), Some(reader))
352363
} else {
353-
(imp::Stdio::Piped(writer), Some(reader))
364+
(imp::Stdio::Raw(writer.raw()), Some(reader), Some(writer))
354365
}
355366
}
356-
StdioImp::Raw(ref raw) => (raw.clone_if_copy(), None),
367+
StdioImp::Raw(ref owned) => (imp::Stdio::Raw(owned.raw()), None, None),
368+
StdioImp::Inherit => (imp::Stdio::Inherit, None, None),
369+
StdioImp::None => (imp::Stdio::None, None, None),
357370
})
358371
}
359372

@@ -379,7 +392,9 @@ pub struct Stdio(StdioImp);
379392
// The internal enum for stdio setup; see below for descriptions.
380393
enum StdioImp {
381394
MakePipe,
382-
Raw(imp::Stdio),
395+
Raw(imp::RawStdio),
396+
Inherit,
397+
None,
383398
}
384399

385400
impl Stdio {
@@ -389,16 +404,16 @@ impl Stdio {
389404

390405
/// The child inherits from the corresponding parent descriptor.
391406
#[stable(feature = "process", since = "1.0.0")]
392-
pub fn inherit() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::Inherit)) }
407+
pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) }
393408

394409
/// This stream will be ignored. This is the equivalent of attaching the
395410
/// stream to `/dev/null`
396411
#[stable(feature = "process", since = "1.0.0")]
397-
pub fn null() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::None)) }
412+
pub fn null() -> Stdio { Stdio(StdioImp::None) }
398413
}
399414

400-
impl FromInner<imp::Stdio> for Stdio {
401-
fn from_inner(inner: imp::Stdio) -> Stdio {
415+
impl FromInner<imp::RawStdio> for Stdio {
416+
fn from_inner(inner: imp::RawStdio) -> Stdio {
402417
Stdio(StdioImp::Raw(inner))
403418
}
404419
}

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

+5-23
Original file line numberDiff line numberDiff line change
@@ -65,46 +65,28 @@ impl ExitStatusExt for process::ExitStatus {
6565
}
6666
}
6767

68-
#[stable(feature = "from_raw_os", since = "1.1.0")]
68+
#[stable(feature = "process_extensions", since = "1.2.0")]
6969
impl FromRawFd for process::Stdio {
70-
/// Creates a new instance of `Stdio` from the raw underlying file
71-
/// descriptor.
72-
///
73-
/// When this `Stdio` is used as an I/O handle for a child process the given
74-
/// file descriptor will be `dup`d into the destination file descriptor in
75-
/// the child process.
76-
///
77-
/// Note that this function **does not** take ownership of the file
78-
/// descriptor provided and it will **not** be closed when `Stdio` goes out
79-
/// of scope. As a result this method is unsafe because due to the lack of
80-
/// knowledge about the lifetime of the provided file descriptor, this could
81-
/// cause another I/O primitive's ownership property of its file descriptor
82-
/// to be violated.
83-
///
84-
/// Also note that this file descriptor may be used multiple times to spawn
85-
/// processes. For example the `Command::spawn` function could be called
86-
/// more than once to spawn more than one process sharing this file
87-
/// descriptor.
8870
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
89-
process::Stdio::from_inner(sys::process::Stdio::Fd(fd))
71+
process::Stdio::from_inner(sys::fd::FileDesc::new(fd))
9072
}
9173
}
9274

93-
#[stable(feature = "from_raw_os", since = "1.1.0")]
75+
#[stable(feature = "process_extensions", since = "1.2.0")]
9476
impl AsRawFd for process::ChildStdin {
9577
fn as_raw_fd(&self) -> RawFd {
9678
self.as_inner().fd().raw()
9779
}
9880
}
9981

100-
#[stable(feature = "from_raw_os", since = "1.1.0")]
82+
#[stable(feature = "process_extensions", since = "1.2.0")]
10183
impl AsRawFd for process::ChildStdout {
10284
fn as_raw_fd(&self) -> RawFd {
10385
self.as_inner().fd().raw()
10486
}
10587
}
10688

107-
#[stable(feature = "from_raw_os", since = "1.1.0")]
89+
#[stable(feature = "process_extensions", since = "1.2.0")]
10890
impl AsRawFd for process::ChildStderr {
10991
fn as_raw_fd(&self) -> RawFd {
11092
self.as_inner().fd().raw()

src/libstd/sys/unix/fs.rs

-2
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,6 @@ impl File {
283283
Ok(File(fd))
284284
}
285285

286-
pub fn into_fd(self) -> FileDesc { self.0 }
287-
288286
pub fn file_attr(&self) -> io::Result<FileAttr> {
289287
let mut stat: raw::stat = unsafe { mem::zeroed() };
290288
try!(cvt(unsafe {

src/libstd/sys/unix/pipe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ impl AnonPipe {
4444
self.0.write(buf)
4545
}
4646

47+
pub fn raw(&self) -> libc::c_int { self.0.raw() }
4748
pub fn fd(&self) -> &FileDesc { &self.0 }
48-
pub fn into_fd(self) -> FileDesc { self.0 }
4949
}

src/libstd/sys/unix/process.rs

+11-22
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ use fmt;
1818
use io::{self, Error, ErrorKind};
1919
use libc::{self, pid_t, c_void, c_int, gid_t, uid_t};
2020
use ptr;
21+
use sys::fd::FileDesc;
22+
use sys::fs::{File, OpenOptions};
2123
use sys::pipe::AnonPipe;
2224
use sys::{self, c, cvt, cvt_r};
23-
use sys::fs::{File, OpenOptions};
2425

2526
////////////////////////////////////////////////////////////////////////////////
2627
// Command
@@ -121,11 +122,12 @@ pub struct Process {
121122

122123
pub enum Stdio {
123124
Inherit,
124-
Piped(AnonPipe),
125125
None,
126-
Fd(c_int),
126+
Raw(c_int),
127127
}
128128

129+
pub type RawStdio = FileDesc;
130+
129131
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
130132

131133
impl Process {
@@ -252,10 +254,9 @@ impl Process {
252254
}
253255

254256
let setup = |src: Stdio, dst: c_int| {
255-
let fd = match src {
256-
Stdio::Inherit => return true,
257-
Stdio::Fd(fd) => return cvt_r(|| libc::dup2(fd, dst)).is_ok(),
258-
Stdio::Piped(pipe) => pipe.into_fd(),
257+
match src {
258+
Stdio::Inherit => true,
259+
Stdio::Raw(fd) => cvt_r(|| libc::dup2(fd, dst)).is_ok(),
259260

260261
// If a stdio file descriptor is set to be ignored, we open up
261262
// /dev/null into that file descriptor. Otherwise, the first
@@ -269,13 +270,12 @@ impl Process {
269270
let devnull = CStr::from_ptr(b"/dev/null\0".as_ptr()
270271
as *const _);
271272
if let Ok(f) = File::open_c(devnull, &opts) {
272-
f.into_fd()
273+
cvt_r(|| libc::dup2(f.fd().raw(), dst)).is_ok()
273274
} else {
274-
return false
275+
false
275276
}
276277
}
277-
};
278-
cvt_r(|| libc::dup2(fd.raw(), dst)).is_ok()
278+
}
279279
};
280280

281281
if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
@@ -418,14 +418,3 @@ fn translate_status(status: c_int) -> ExitStatus {
418418
ExitStatus::Signal(imp::WTERMSIG(status))
419419
}
420420
}
421-
422-
impl Stdio {
423-
pub fn clone_if_copy(&self) -> Stdio {
424-
match *self {
425-
Stdio::Inherit => Stdio::Inherit,
426-
Stdio::None => Stdio::None,
427-
Stdio::Fd(fd) => Stdio::Fd(fd),
428-
Stdio::Piped(_) => unreachable!(),
429-
}
430-
}
431-
}

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

+8-23
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,43 @@
1010

1111
//! Extensions to `std::process` for Windows.
1212
13-
#![stable(feature = "from_raw_os", since = "1.1.0")]
13+
#![stable(feature = "process_extensions", since = "1.2.0")]
1414

1515
use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle};
1616
use process;
1717
use sys;
1818
use sys_common::{AsInner, FromInner};
1919

20-
#[stable(feature = "from_raw_os", since = "1.1.0")]
20+
#[stable(feature = "process_extensions", since = "1.2.0")]
2121
impl FromRawHandle for process::Stdio {
22-
/// Creates a new instance of `Stdio` from the raw underlying handle.
23-
///
24-
/// When this `Stdio` is used as an I/O handle for a child process the given
25-
/// handle will be duplicated via `DuplicateHandle` to ensure that the
26-
/// handle has the correct permissions to cross the process boundary.
27-
///
28-
/// Note that this function **does not** take ownership of the handle
29-
/// provided and it will **not** be closed when `Stdio` goes out of scope.
30-
/// As a result this method is unsafe because due to the lack of knowledge
31-
/// about the lifetime of the provided handle, this could cause another I/O
32-
/// primitive's ownership property of its handle to be violated.
33-
///
34-
/// Also note that this handle may be used multiple times to spawn
35-
/// processes. For example the `Command::spawn` function could be called
36-
/// more than once to spawn more than one process sharing this handle.
3722
unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
38-
let handle = sys::handle::RawHandle::new(handle as *mut _);
39-
process::Stdio::from_inner(sys::process::Stdio::Handle(handle))
23+
let handle = sys::handle::Handle::new(handle as *mut _);
24+
process::Stdio::from_inner(handle)
4025
}
4126
}
4227

43-
#[stable(feature = "from_raw_os", since = "1.1.0")]
28+
#[stable(feature = "process_extensions", since = "1.2.0")]
4429
impl AsRawHandle for process::Child {
4530
fn as_raw_handle(&self) -> RawHandle {
4631
self.as_inner().handle().raw() as *mut _
4732
}
4833
}
4934

50-
#[stable(feature = "from_raw_os", since = "1.1.0")]
35+
#[stable(feature = "process_extensions", since = "1.2.0")]
5136
impl AsRawHandle for process::ChildStdin {
5237
fn as_raw_handle(&self) -> RawHandle {
5338
self.as_inner().handle().raw() as *mut _
5439
}
5540
}
5641

57-
#[stable(feature = "from_raw_os", since = "1.1.0")]
42+
#[stable(feature = "process_extensions", since = "1.2.0")]
5843
impl AsRawHandle for process::ChildStdout {
5944
fn as_raw_handle(&self) -> RawHandle {
6045
self.as_inner().handle().raw() as *mut _
6146
}
6247
}
6348

64-
#[stable(feature = "from_raw_os", since = "1.1.0")]
49+
#[stable(feature = "process_extensions", since = "1.2.0")]
6550
impl AsRawHandle for process::ChildStderr {
6651
fn as_raw_handle(&self) -> RawHandle {
6752
self.as_inner().handle().raw() as *mut _

src/libstd/sys/windows/pipe.rs

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
3838
impl AnonPipe {
3939
pub fn handle(&self) -> &Handle { &self.inner }
4040

41+
pub fn raw(&self) -> libc::HANDLE { self.inner.raw() }
42+
4143
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
4244
self.inner.read(buf)
4345
}

src/libstd/sys/windows/process.rs

+5-17
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use sync::StaticMutex;
2828
use sys::c;
2929
use sys::fs::{OpenOptions, File};
3030
use sys::handle::{Handle, RawHandle};
31-
use sys::pipe::AnonPipe;
3231
use sys::stdio;
3332
use sys::{self, cvt};
3433
use sys_common::{AsInner, FromInner};
@@ -107,11 +106,12 @@ pub struct Process {
107106

108107
pub enum Stdio {
109108
Inherit,
110-
Piped(AnonPipe),
111109
None,
112-
Handle(RawHandle),
110+
Raw(libc::HANDLE),
113111
}
114112

113+
pub type RawStdio = Handle;
114+
115115
impl Process {
116116
pub fn spawn(cfg: &Command,
117117
in_handle: Stdio,
@@ -356,15 +356,6 @@ fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) {
356356
}
357357

358358
impl Stdio {
359-
pub fn clone_if_copy(&self) -> Stdio {
360-
match *self {
361-
Stdio::Inherit => Stdio::Inherit,
362-
Stdio::None => Stdio::None,
363-
Stdio::Handle(handle) => Stdio::Handle(handle),
364-
Stdio::Piped(_) => unreachable!(),
365-
}
366-
}
367-
368359
fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result<Handle> {
369360
use libc::DUPLICATE_SAME_ACCESS;
370361

@@ -374,11 +365,8 @@ impl Stdio {
374365
io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
375366
})
376367
}
377-
Stdio::Handle(ref handle) => {
378-
handle.duplicate(0, true, DUPLICATE_SAME_ACCESS)
379-
}
380-
Stdio::Piped(ref pipe) => {
381-
pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
368+
Stdio::Raw(handle) => {
369+
RawHandle::new(handle).duplicate(0, true, DUPLICATE_SAME_ACCESS)
382370
}
383371

384372
// Similarly to unix, we don't actually leave holes for the

0 commit comments

Comments
 (0)