From 46315184cb74a98dbd10a0d300a0c3ee62b78049 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 4 Feb 2016 15:22:41 -0800 Subject: [PATCH] std: Add support for accept4 on Linux This is necessary to atomically accept a socket and set the CLOEXEC flag at the same time. Support only appeared in Linux 2.6.28 so we have to dynamically determine which syscall we're supposed to call in this case. --- src/libstd/sys/unix/net.rs | 26 +++++++++++++++++++++++--- src/libstd/sys/unix/weak.rs | 6 +++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 728bc258c00a8..507cc0f4ea461 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -12,7 +12,7 @@ use prelude::v1::*; use ffi::CStr; use io; -use libc::{self, c_int, size_t}; +use libc::{self, c_int, size_t, sockaddr, socklen_t}; use net::{SocketAddr, Shutdown}; use str; use sys::fd::FileDesc; @@ -78,8 +78,28 @@ impl Socket { } } - pub fn accept(&self, storage: *mut libc::sockaddr, - len: *mut libc::socklen_t) -> io::Result { + 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. + if cfg!(target_os = "linux") { + weak! { + fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int + } + if let Some(accept) = accept4.get() { + let res = cvt_r(|| unsafe { + accept(self.0.raw(), storage, len, 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), + } + } + } + let fd = try!(cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })); diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 2cbcd62f53396..e6f85c08d1246 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -61,7 +61,11 @@ impl Weak { if self.addr.load(Ordering::SeqCst) == 1 { self.addr.store(fetch(self.name), Ordering::SeqCst); } - mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) + if self.addr.load(Ordering::SeqCst) == 0 { + None + } else { + mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) + } } } }