diff --git a/Makefile b/Makefile index d46c20b72..eb2dab5ed 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Targets available via Rustup that are supported. -TARGETS ?= "aarch64-apple-ios" "aarch64-linux-android" "x86_64-apple-darwin" "x86_64-pc-windows-msvc" "x86_64-unknown-freebsd" "x86_64-unknown-illumos" "x86_64-unknown-linux-gnu" "x86_64-unknown-netbsd" +TARGETS ?= aarch64-apple-ios aarch64-linux-android x86_64-apple-darwin x86_64-pc-windows-msvc x86_64-unknown-freebsd x86_64-unknown-illumos x86_64-unknown-linux-gnu x86_64-unknown-netbsd test: cargo test --all-features diff --git a/src/sys/unix/selector/epoll.rs b/src/sys/unix/selector/epoll.rs index 477642a12..074d3a8ef 100644 --- a/src/sys/unix/selector/epoll.rs +++ b/src/sys/unix/selector/epoll.rs @@ -23,7 +23,40 @@ pub struct Selector { impl Selector { pub fn new() -> io::Result { - let ep = new_epoll_fd()?; + #[cfg(not(target_os = "android"))] + let res = syscall!(epoll_create1(libc::O_CLOEXEC)); + + // On Android < API level 16 `epoll_create1` is not defined, so use a + // raw system call. + // According to libuv, `EPOLL_CLOEXEC` is not defined on Android API < + // 21. But `EPOLL_CLOEXEC` is an alias for `O_CLOEXEC` on that platform, + // so we use it instead. + #[cfg(target_os = "android")] + let res = syscall!(syscall(libc::SYS_epoll_create1, libc::EPOLL_CLOEXEC)); + + let ep = match res { + Ok(ep) => ep as RawFd, + Err(err) => { + // When `epoll_create1` is not available fall back to use + // `epoll_create` followed by `fcntl`. + if let Some(libc::ENOSYS) = err.raw_os_error() { + match syscall!(epoll_create(1024)) { + Ok(ep) => match syscall!(fcntl(ep, libc::F_SETFD, libc::FD_CLOEXEC)) { + Ok(ep) => ep as RawFd, + Err(err) => { + // `fcntl` failed, cleanup `ep`. + let _ = unsafe { libc::close(ep) }; + return Err(err); + } + }, + Err(err) => return Err(err), + } + } else { + return Err(err); + } + } + }; + Ok(Selector { #[cfg(debug_assertions)] id: NEXT_ID.fetch_add(1, Ordering::Relaxed), @@ -126,43 +159,6 @@ impl Drop for Selector { } } -/// Creates a new epoll file descriptor with close-on-exec flag set. -/// -/// close-on-exec is set atomically with `epoll_create1()` if possible, -/// otherwise `epoll_create()` and `fcntl()` calls are used as a fallback. -fn new_epoll_fd() -> io::Result { - // According to libuv, `EPOLL_CLOEXEC` is not defined on Android API < - // 21. But `EPOLL_CLOEXEC` is an alias for `O_CLOEXEC` on that platform, - // so we use it instead. - #[cfg(target_os = "android")] - let flag = libc::O_CLOEXEC; - #[cfg(not(target_os = "android"))] - let flag = libc::EPOLL_CLOEXEC; - - #[cfg(not(target_os = "android"))] - let ep = syscall!(epoll_create1(flag))?; - - // On Android try to use epoll_create1 syscall with an epoll_create fallback - // to support Android API level 16 which does not define epoll_create1 function. - #[cfg(target_os = "android")] - let ep = syscall!(syscall(libc::SYS_epoll_create1, flag)) - .map(|fd| fd as libc::c_int) - .or_else(|e| { - match e.raw_os_error() { - Some(libc::ENOSYS) => { - // Using epoll_create() followed by fcntl() instead of epoll_create1() with EPOLL_CLOEXEC - // flag for backwards compatibility. - let ep = syscall!(epoll_create(1024))?; - - syscall!(fcntl(ep, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| ep) - } - _ => Err(e), - } - })?; - - Ok(ep) -} - fn interests_to_epoll(interests: Interest) -> u32 { let mut kind = EPOLLET;