aboutsummaryrefslogtreecommitdiff
path: root/src/sys/unix/selector/epoll.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/unix/selector/epoll.rs')
-rw-r--r--src/sys/unix/selector/epoll.rs54
1 files changed, 48 insertions, 6 deletions
diff --git a/src/sys/unix/selector/epoll.rs b/src/sys/unix/selector/epoll.rs
index 38667d6..1256663 100644
--- a/src/sys/unix/selector/epoll.rs
+++ b/src/sys/unix/selector/epoll.rs
@@ -23,15 +23,41 @@ pub struct Selector {
impl Selector {
pub fn new() -> io::Result<Selector> {
+ #[cfg(not(target_os = "android"))]
+ let res = syscall!(epoll_create1(libc::EPOLL_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 flag = libc::O_CLOEXEC;
- #[cfg(not(target_os = "android"))]
- let flag = libc::EPOLL_CLOEXEC;
+ let res = syscall!(syscall(libc::SYS_epoll_create1, libc::O_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);
+ }
+ }
+ };
- syscall!(epoll_create1(flag)).map(|ep| Selector {
+ Ok(Selector {
#[cfg(debug_assertions)]
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
ep,
@@ -61,7 +87,19 @@ impl Selector {
const MAX_SAFE_TIMEOUT: u128 = libc::c_int::max_value() as u128;
let timeout = timeout
- .map(|to| cmp::min(to.as_millis(), MAX_SAFE_TIMEOUT) as libc::c_int)
+ .map(|to| {
+ let to_ms = to.as_millis();
+ // as_millis() truncates, so round up to 1 ms as the documentation says can happen.
+ // This avoids turning submillisecond timeouts into immediate returns unless the
+ // caller explicitly requests that by specifying a zero timeout.
+ let to_ms = to_ms
+ + if to_ms == 0 && to.subsec_nanos() != 0 {
+ 1
+ } else {
+ 0
+ };
+ cmp::min(MAX_SAFE_TIMEOUT, to_ms) as libc::c_int
+ })
.unwrap_or(-1);
events.clear();
@@ -82,6 +120,8 @@ impl Selector {
let mut event = libc::epoll_event {
events: interests_to_epoll(interests),
u64: usize::from(token) as u64,
+ #[cfg(target_os = "redox")]
+ _pad: 0,
};
syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_ADD, fd, &mut event)).map(|_| ())
@@ -91,6 +131,8 @@ impl Selector {
let mut event = libc::epoll_event {
events: interests_to_epoll(interests),
u64: usize::from(token) as u64,
+ #[cfg(target_os = "redox")]
+ _pad: 0,
};
syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_MOD, fd, &mut event)).map(|_| ())
@@ -222,7 +264,7 @@ pub mod event {
libc::EPOLLET,
libc::EPOLLRDHUP,
libc::EPOLLONESHOT,
- #[cfg(any(target_os = "linux", target_os = "solaris"))]
+ #[cfg(target_os = "linux")]
libc::EPOLLEXCLUSIVE,
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::EPOLLWAKEUP,