Skip to content

Commit 4631518

Browse files
committed
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.
1 parent 1a31e1c commit 4631518

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

src/libstd/sys/unix/net.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use prelude::v1::*;
1212

1313
use ffi::CStr;
1414
use io;
15-
use libc::{self, c_int, size_t};
15+
use libc::{self, c_int, size_t, sockaddr, socklen_t};
1616
use net::{SocketAddr, Shutdown};
1717
use str;
1818
use sys::fd::FileDesc;
@@ -78,8 +78,28 @@ impl Socket {
7878
}
7979
}
8080

81-
pub fn accept(&self, storage: *mut libc::sockaddr,
82-
len: *mut libc::socklen_t) -> io::Result<Socket> {
81+
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
82+
-> io::Result<Socket> {
83+
// Unfortunately the only known way right now to accept a socket and
84+
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
85+
// Linux. This was added in 2.6.28, however, and because we support
86+
// 2.6.18 we must detect this support dynamically.
87+
if cfg!(target_os = "linux") {
88+
weak! {
89+
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
90+
}
91+
if let Some(accept) = accept4.get() {
92+
let res = cvt_r(|| unsafe {
93+
accept(self.0.raw(), storage, len, SOCK_CLOEXEC)
94+
});
95+
match res {
96+
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
97+
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
98+
Err(e) => return Err(e),
99+
}
100+
}
101+
}
102+
83103
let fd = try!(cvt_r(|| unsafe {
84104
libc::accept(self.0.raw(), storage, len)
85105
}));

src/libstd/sys/unix/weak.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ impl<F> Weak<F> {
6161
if self.addr.load(Ordering::SeqCst) == 1 {
6262
self.addr.store(fetch(self.name), Ordering::SeqCst);
6363
}
64-
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
64+
if self.addr.load(Ordering::SeqCst) == 0 {
65+
None
66+
} else {
67+
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
68+
}
6569
}
6670
}
6771
}

0 commit comments

Comments
 (0)