Skip to content

Commit

Permalink
std: Try to use pipe2 on Linux for pipes
Browse files Browse the repository at this point in the history
This commit attempts to use the `pipe2` syscall on Linux to atomically set the
CLOEXEC flag for pipes created. Unfortunately this was added in 2.6.27 so we
have to dynamically determine whether we can use it or not.

This commit also updates the `fds-are-cloexec.rs` test to test stdio handles for
spawned processes as well.
  • Loading branch information
alexcrichton committed Feb 6, 2016
1 parent 4631518 commit 812b309
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
23 changes: 21 additions & 2 deletions src/libstd/sys/unix/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use sys::fd::FileDesc;
use io;
use libc;
use libc::{self, c_int};
use sys::cvt_r;
use sys::fd::FileDesc;

////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
Expand All @@ -20,6 +21,24 @@ pub struct AnonPipe(FileDesc);

pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
let mut fds = [0; 2];

// Unfortunately the only known way right now to create atomically set the
// CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
// 2.6.27, however, and because we support 2.6.18 we must detect this
// support dynamically.
if cfg!(target_os = "linux") {
weak! { fn pipe2(*mut c_int, c_int) -> c_int }
if let Some(pipe) = pipe2.get() {
match cvt_r(|| unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
Ok(_) => {
return Ok((AnonPipe(FileDesc::new(fds[0])),
AnonPipe(FileDesc::new(fds[1]))))
}
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
Err(e) => return Err(e),
}
}
}
if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } {
Ok((AnonPipe::from_fd(fds[0]), AnonPipe::from_fd(fds[1])))
} else {
Expand Down
19 changes: 17 additions & 2 deletions src/test/run-pass/fds-are-cloexec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
extern crate libc;

use std::env;
use std::fs::{self, File};
use std::fs::File;
use std::io;
use std::net::{TcpListener, TcpStream, UdpSocket};
use std::os::unix::prelude::*;
use std::process::Command;
use std::process::{Command, Stdio};
use std::thread;

fn main() {
Expand All @@ -45,6 +45,17 @@ fn parent() {
let udp1 = UdpSocket::bind("127.0.0.1:0").unwrap();
let udp2 = udp1.try_clone().unwrap();

let mut child = Command::new(env::args().next().unwrap())
.arg("100")
.stdout(Stdio::piped())
.stdin(Stdio::piped())
.stderr(Stdio::piped())
.spawn().unwrap();
let pipe1 = child.stdin.take().unwrap();
let pipe2 = child.stdout.take().unwrap();
let pipe3 = child.stderr.take().unwrap();


let status = Command::new(env::args().next().unwrap())
.arg(file.as_raw_fd().to_string())
.arg(tcp1.as_raw_fd().to_string())
Expand All @@ -55,9 +66,13 @@ fn parent() {
.arg(tcp6.as_raw_fd().to_string())
.arg(udp1.as_raw_fd().to_string())
.arg(udp2.as_raw_fd().to_string())
.arg(pipe1.as_raw_fd().to_string())
.arg(pipe2.as_raw_fd().to_string())
.arg(pipe3.as_raw_fd().to_string())
.status()
.unwrap();
assert!(status.success());
child.wait().unwrap();
}

fn child(args: &[String]) {
Expand Down

0 comments on commit 812b309

Please sign in to comment.