diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index b746b0feb623b..84c4d662161bc 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -3,7 +3,6 @@ use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; -use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::cvt; use crate::sys_common::AsInner; @@ -224,50 +223,9 @@ impl FileDesc { pub fn duplicate(&self) -> io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // flag, however, isn't supported on older Linux kernels (earlier than - // 2.6.24). - // - // To detect this and ensure that CLOEXEC is still set, we - // follow a strategy similar to musl [1] where if passing - // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not - // supported (the third parameter, 0, is always valid), so we stop - // trying that. - // - // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to - // resolve so we at least compile this. - // - // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(any(target_os = "android", target_os = "haiku"))] - use libc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(any(target_os = "android", target_os = "haiku")))] - use libc::F_DUPFD_CLOEXEC; - - let make_filedesc = |fd| { - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(fd) - }; - static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android")); - let fd = self.raw(); - if TRY_CLOEXEC.load(Ordering::Relaxed) { - match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { - // We *still* call the `set_cloexec` method as apparently some - // linux kernel at some point stopped setting CLOEXEC even - // though it reported doing so on F_DUPFD_CLOEXEC. - Ok(fd) => { - return Ok(if cfg!(target_os = "linux") { - make_filedesc(fd)? - } else { - FileDesc::new(fd) - }); - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { - TRY_CLOEXEC.store(false, Ordering::Relaxed); - } - Err(e) => return Err(e), - } - } - cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc) + // is a POSIX flag that was added to Linux in 2.6.24. + let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?; + Ok(FileDesc::new(fd)) } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 29cdbf05354fb..acb18e6d064e6 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -708,56 +708,7 @@ impl File { // However, since this is a variadic function, C integer promotion rules mean that on // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; - let fd = FileDesc::new(fd); - - // Currently the standard library supports Linux 2.6.18 which did not - // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS. After we open - // the first file, we check whether it has CLOEXEC set. If it doesn't, - // we will explicitly ask for a CLOEXEC fd for every further file we - // open, if it does, we will skip that step. - // - // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc - // that we support, so we only do this on Linux currently. - #[cfg(target_os = "linux")] - fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { - use crate::sync::atomic::{AtomicUsize, Ordering}; - - const OPEN_CLOEXEC_UNKNOWN: usize = 0; - const OPEN_CLOEXEC_SUPPORTED: usize = 1; - const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; - static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); - - let need_to_set; - match OPEN_CLOEXEC.load(Ordering::Relaxed) { - OPEN_CLOEXEC_UNKNOWN => { - need_to_set = !fd.get_cloexec()?; - OPEN_CLOEXEC.store( - if need_to_set { - OPEN_CLOEXEC_NOTSUPPORTED - } else { - OPEN_CLOEXEC_SUPPORTED - }, - Ordering::Relaxed, - ); - } - OPEN_CLOEXEC_SUPPORTED => need_to_set = false, - OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, - _ => unreachable!(), - } - if need_to_set { - fd.set_cloexec()?; - } - Ok(()) - } - - #[cfg(not(target_os = "linux"))] - fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { - Ok(()) - } - - ensure_cloexec(&fd)?; - Ok(File(fd)) + Ok(File(FileDesc::new(fd))) } pub fn file_attr(&self) -> io::Result { diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 3717c660b575d..011325fddc5b9 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -54,31 +54,26 @@ impl Socket { pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { unsafe { - // On linux we first attempt to pass the SOCK_CLOEXEC flag to - // atomically create the socket and set it as CLOEXEC. Support for - // this option, however, was added in 2.6.27, and we still support - // 2.6.18 as a kernel, so if the returned error is EINVAL we - // fallthrough to the fallback. - #[cfg(target_os = "linux")] - { - match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} - Err(e) => return Err(e), - } - } - - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // On Linux we pass the SOCK_CLOEXEC flag to atomically create + // the socket and set it as CLOEXEC, added in 2.6.27. + let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; + Ok(Socket(FileDesc::new(fd))) + } else { + let fd = cvt(libc::socket(fam, ty, 0))?; + let fd = FileDesc::new(fd); + fd.set_cloexec()?; + let socket = Socket(fd); - // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` - // flag to disable `SIGPIPE` emission on socket. - #[cfg(target_vendor = "apple")] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(target_vendor = "apple")] + setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; - Ok(socket) + Ok(socket) + } + } } } @@ -86,24 +81,20 @@ impl Socket { unsafe { let mut fds = [0, 0]; - // Like above, see if we can set cloexec atomically - #[cfg(target_os = "linux")] - { - match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { - Ok(_) => { - return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} - Err(e) => return Err(e), + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // Like above, set cloexec atomically + cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; + Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))) + } else { + cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; + let a = FileDesc::new(fds[0]); + let b = FileDesc::new(fds[1]); + a.set_cloexec()?; + b.set_cloexec()?; + Ok((Socket(a), Socket(b))) } } - - cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); - a.set_cloexec()?; - b.set_cloexec()?; - Ok((Socket(a), Socket(b))) } } @@ -177,30 +168,20 @@ impl Socket { pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { // Unfortunately the only known way right now to accept a socket and // atomically set the CLOEXEC flag is to use the `accept4` syscall on - // Linux. This was added in 2.6.28, however, and because we support - // 2.6.18 we must detect this support dynamically. - #[cfg(target_os = "linux")] - { - syscall! { - fn accept4( - fd: c_int, - addr: *mut sockaddr, - addr_len: *mut socklen_t, - flags: c_int - ) -> c_int - } - let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) }); - match res { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), + // Linux. This was added in 2.6.28, glibc 2.10 and musl 0.9.5. + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + let fd = cvt_r(|| unsafe { + libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) + })?; + Ok(Socket(FileDesc::new(fd))) + } else { + let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; + let fd = FileDesc::new(fd); + fd.set_cloexec()?; + Ok(Socket(fd)) } } - - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) } pub fn duplicate(&self) -> io::Result { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index a9cd5094997bd..2fcb5b9c4e66e 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -71,6 +71,7 @@ pub fn errno() -> i32 { /// Sets the platform-specific value of errno #[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall! +#[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index f2a2eabef9132..7ae37bdda70bd 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -1,11 +1,8 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; -use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::fd::FileDesc; use crate::sys::{cvt, cvt_r}; -use libc::c_int; - //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes //////////////////////////////////////////////////////////////////////////////// @@ -13,46 +10,32 @@ use libc::c_int; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int } - static INVALID: AtomicBool = AtomicBool::new(false); - 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!(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox" - )) && !INVALID.load(Ordering::SeqCst) - { - // 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 { pipe2(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), + // The only known way right now to create atomically set the CLOEXEC flag is + // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9 + // and musl 0.9.3, and some other targets also have it. + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox" + ))] { + cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; + Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) + } else { + cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; + + let fd0 = FileDesc::new(fds[0]); + let fd1 = FileDesc::new(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((AnonPipe(fd0), AnonPipe(fd1))) } } - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) } impl AnonPipe { diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 08cbe59617465..f4b33a00f7c85 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -16,6 +16,11 @@ //! symbol, but that caused Debian to detect an unnecessarily strict versioned //! dependency on libc6 (#23628). +// There are a variety of `#[cfg]`s controlling which targets are involved in +// each instance of `weak!` and `syscall!`. Rather than trying to unify all of +// that, we'll just allow that some unix targets don't use this module at all. +#![allow(dead_code, unused_macros)] + use crate::ffi::CStr; use crate::marker; use crate::mem;