Use raw system call for epoll_create1() on Android

Using epoll_create() as a fallback.

Fix #1473.
This commit is contained in:
link2xt
2022-07-17 22:44:35 +03:00
committed by GitHub
parent 0f6d1b8854
commit 43aa8c5589
2 changed files with 46 additions and 9 deletions
+7
View File
@@ -263,6 +263,13 @@ impl Poll {
/// the system selector. If this syscall fails, `Poll::new` will return
/// with the error.
///
/// close-on-exec flag is set on the file descriptors used by the selector to prevent
/// leaking it to executed processes. However, on some systems such as
/// old Linux systems that don't support `epoll_create1` syscall it is done
/// non-atomically, so a separate thread executing in parallel to this
/// function may accidentally leak the file descriptor if it executes a
/// new process before this function returns.
///
/// See [struct] level docs for more details.
///
/// [struct]: struct.Poll.html
+39 -9
View File
@@ -23,15 +23,8 @@ pub struct Selector {
impl Selector {
pub fn new() -> io::Result<Selector> {
// 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;
syscall!(epoll_create1(flag)).map(|ep| Selector {
let ep = new_epoll_fd()?;
Ok(Selector {
#[cfg(debug_assertions)]
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
ep,
@@ -133,6 +126,43 @@ 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<libc::c_int> {
// 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;