use libc::{self, c_int}; use std::{io, ptr, time}; pub(crate) type FileDescriptor = c_int; pub(crate) trait AsFileDescriptor { fn as_file_descriptor(&self) -> FileDescriptor; } pub(crate) struct UserData(u64); #[inline] pub(crate) fn register_polling( poller: &Poller, entity: F, user: UserData, read: bool, write: bool ) -> io::Result<()> { let file_descriptor = entity.as_file_descriptor(); return poller.register(file_descriptor, user, read, write); } #[inline] pub(crate) fn unregister_polling( poller: &Poller, entity: F ) -> io::Result<()> { let file_descriptor = entity.as_file_descriptor(); return poller.unregister(file_descriptor); } #[cfg(unix)] pub(crate) struct Poller { handle: c_int, events: Vec } // All of this is gleaned from the `mio` crate. #[cfg(unix)] impl Poller { pub fn new(event_capacity: usize) -> io::Result { assert!(event_capacity < i32::MAX as usize); // because of argument to `epoll_wait`. let handle = syscall_result(unsafe{ libc::epoll_create1(libc::EPOLL_CLOEXEC) })?; return Ok(Self{ handle, events: Vec::with_capacity(event_capacity), }) } fn register(&self, fd: FileDescriptor, user: UserData, read: bool, write: bool) -> io::Result<()> { let mut event = libc::epoll_event{ events: Self::events_from_rw_flags(read, write), u64: user.0, }; syscall_result(unsafe{ libc::epoll_ctl(self.handle, libc::EPOLL_CTL_ADD, fd, &mut event) })?; return Ok(()); } fn unregister(&self, fd: FileDescriptor) -> io::Result<()> { syscall_result(unsafe{ libc::epoll_ctl(self.handle, libc::EPOLL_CTL_DEL, fd, ptr::null_mut()) })?; return Ok(()); } pub fn wait(&mut self, timeout: time::Duration) -> io::Result<()> { // See `mio` for the reason. Works around a linux bug #[cfg(target_pointer_width = "32")] const MAX_TIMEOUT: u128 = 1789569; #[cfg(not(target_pointer_width = "32"))] const MAX_TIMEOUT: u128 = c_int::MAX as u128; let mut timeout_millis = timeout.as_millis(); if timeout_millis > MAX_TIMEOUT { timeout_millis = -1; // effectively infinite } let num_events = syscall_result(unsafe{ libc::epoll_wait(self.handle, self.events.as_mut(), self.events.capacity() as i32, timeout_millis) })?; unsafe{ debug_assert!(num_events >= 0); self.events.set_len(num_events as usize); } return Ok(()); } fn events_from_rw_flags(read: bool, write: bool) -> u32 { let mut events = libc::EPOLLET; if read { events |= libc::EPOLLIN | libc::EPOLLRDHUP; } if write { events |= libc::EPOLLOUT; } return events as u32; } } #[inline] fn syscall_result(result: c_int) -> io::Result { if result < 0 { return Err(io::Error::last_os_error()); } else { return Ok(result); } } #[cfg(not(unix))] struct Poller { }