about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-06-09 10:28:12 +0000
committerbors <bors@rust-lang.org>2017-06-09 10:28:12 +0000
commita7ac71b97899f1fac87a70c87a2b98e46877918b (patch)
tree66dba336878643be9dd65fb0fd414b0ba19ce6d4
parent19193d6390644b5d621934bac6a33caacfb9ad31 (diff)
parent44e6406f9a29e03280f4e16434c06e1d0abfaffc (diff)
downloadrust-a7ac71b97899f1fac87a70c87a2b98e46877918b.tar.gz
rust-a7ac71b97899f1fac87a70c87a2b98e46877918b.zip
Auto merge of #42521 - alexcrichton:enosys, r=cuviper
std: Handle ENOSYS when calling `pipe2`

Should help fix an accidental regression from #39386.
-rw-r--r--src/libstd/sys/unix/pipe.rs29
1 files changed, 23 insertions, 6 deletions
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 706256ff10e..ca5ef4bcfc5 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()) })?;