about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-06-07 18:31:35 -0700
committerAlex Crichton <alex@alexcrichton.com>2017-06-08 07:31:05 -0700
commit44e6406f9a29e03280f4e16434c06e1d0abfaffc (patch)
treef3e8ce08ebd80311db2dba53b4fcf3c1e30c0a7e /src/libstd/sys
parent03eb7109c722117322064390bc66578cde3f7b8e (diff)
downloadrust-44e6406f9a29e03280f4e16434c06e1d0abfaffc.tar.gz
rust-44e6406f9a29e03280f4e16434c06e1d0abfaffc.zip
std: Handle ENOSYS when calling `pipe2`
Should help fix an accidental regression from #39386.
Diffstat (limited to 'src/libstd/sys')
-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()) })?;