From 44e6406f9a29e03280f4e16434c06e1d0abfaffc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 7 Jun 2017 18:31:35 -0700 Subject: [PATCH] std: Handle ENOSYS when calling `pipe2` Should help fix an accidental regression from #39386. --- src/libstd/sys/unix/pipe.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 706256ff10ec9..ca5ef4bcfc5f4 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -11,8 +11,9 @@ use io; use libc::{self, c_int}; use mem; -use sys::{cvt, cvt_r}; +use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use sys::fd::FileDesc; +use sys::{cvt, cvt_r}; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -21,6 +22,9 @@ use sys::fd::FileDesc; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + weak! { fn pipe2(*mut c_int, c_int) -> c_int } + static INVALID: AtomicBool = ATOMIC_BOOL_INIT; + let mut fds = [0; 2]; // Unfortunately the only known way right now to create atomically set the @@ -31,13 +35,26 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "freebsd", target_os = "linux", target_os = "netbsd", - target_os = "openbsd")) + target_os = "openbsd")) && + !INVALID.load(Ordering::SeqCst) { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } + if let Some(pipe) = pipe2.get() { - cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); + // Note that despite calling a glibc function here we may still + // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to + // emulate on older kernels, so if you happen to be running on + // an older kernel you may see `pipe2` as a symbol but still not + // see the syscall. + match cvt(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) => { + INVALID.store(true, Ordering::SeqCst); + } + Err(e) => return Err(e), + } } } cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;