refactor: use libc for epoll

This commit is contained in:
dignifiedquire 2020-05-24 17:08:49 +02:00
parent 63ffbc575c
commit a56aa12de8
4 changed files with 111 additions and 37 deletions

View File

@ -44,7 +44,6 @@ features = ["rt-threaded"]
optional = true
[target.'cfg(unix)'.dependencies]
nix = "0.17.0"
libc = "0.2.70"
[target.'cfg(windows)'.dependencies]

View File

@ -678,7 +678,7 @@ impl Async<TcpStream> {
socket.connect(&addr.into()).or_else(|err| {
// Check for EINPROGRESS on Unix and WSAEWOULDBLOCK on Windows.
#[cfg(unix)]
let in_progress = err.raw_os_error() == Some(crate::sys::libc::EINPROGRESS);
let in_progress = err.raw_os_error() == Some(libc::EINPROGRESS);
#[cfg(windows)]
let in_progress = err.kind() == io::ErrorKind::WouldBlock;
@ -1006,7 +1006,7 @@ impl Async<UnixStream> {
socket
.connect(&socket2::SockAddr::unix(path)?)
.or_else(|err| {
if err.raw_os_error() == Some(crate::sys::libc::EINPROGRESS) {
if err.raw_os_error() == Some(libc::EINPROGRESS) {
Ok(())
} else {
Err(err)

View File

@ -430,15 +430,6 @@ impl Source {
}
}
/// Converts a [`nix::Error`] into [`io::Error`].
#[cfg(unix)]
fn io_err(err: nix::Error) -> io::Error {
match err {
nix::Error::Sys(code) => code.into(),
err => io::Error::new(io::ErrorKind::Other, Box::new(err)),
}
}
/// Raw bindings to epoll (Linux, Android, illumos).
#[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))]
mod sys {
@ -448,23 +439,21 @@ mod sys {
use std::time::Duration;
use crate::sys::epoll::{
epoll_create1, epoll_ctl, epoll_wait, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
epoll_create1, epoll_ctl, epoll_wait, EpollEvent, EpollFlags, EpollOp,
};
use super::io_err;
pub struct Reactor(RawFd);
impl Reactor {
pub fn new() -> io::Result<Reactor> {
let epoll_fd = epoll_create1(EpollCreateFlags::EPOLL_CLOEXEC).map_err(io_err)?;
let epoll_fd = epoll_create1()?;
Ok(Reactor(epoll_fd))
}
pub fn register(&self, fd: RawFd, key: usize) -> io::Result<()> {
let ev = &mut EpollEvent::new(EpollFlags::empty(), key as u64);
epoll_ctl(self.0, EpollOp::EpollCtlAdd, fd, Some(ev)).map_err(io_err)
let ev = &mut EpollEvent::new(0, key as u64);
epoll_ctl(self.0, EpollOp::EpollCtlAdd, fd, Some(ev))
}
pub fn reregister(&self, fd: RawFd, key: usize, read: bool, write: bool) -> io::Result<()> {
let mut flags = EpollFlags::EPOLLONESHOT;
let mut flags = libc::EPOLLONESHOT;
if read {
flags |= read_flags();
}
@ -472,10 +461,10 @@ mod sys {
flags |= write_flags();
}
let ev = &mut EpollEvent::new(flags, key as u64);
epoll_ctl(self.0, EpollOp::EpollCtlMod, fd, Some(ev)).map_err(io_err)
epoll_ctl(self.0, EpollOp::EpollCtlMod, fd, Some(ev))
}
pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
epoll_ctl(self.0, EpollOp::EpollCtlDel, fd, None).map_err(io_err)
epoll_ctl(self.0, EpollOp::EpollCtlDel, fd, None)
}
pub fn wait(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
let timeout_ms = timeout
@ -488,15 +477,15 @@ mod sys {
})
.and_then(|t| t.as_millis().try_into().ok())
.unwrap_or(-1);
events.len = epoll_wait(self.0, &mut events.list, timeout_ms).map_err(io_err)?;
events.len = epoll_wait(self.0, &mut events.list, timeout_ms)?;
Ok(events.len)
}
}
fn read_flags() -> EpollFlags {
EpollFlags::EPOLLIN | EpollFlags::EPOLLRDHUP
libc::EPOLLIN | libc::EPOLLRDHUP
}
fn write_flags() -> EpollFlags {
EpollFlags::EPOLLOUT
libc::EPOLLOUT
}
pub struct Events {
@ -511,8 +500,8 @@ mod sys {
}
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
self.list[..self.len].iter().map(|ev| Event {
readable: ev.events().intersects(read_flags()),
writable: ev.events().intersects(write_flags()),
readable: (ev.events() & read_flags()) > 0,
writable: (ev.events() & write_flags()) > 0,
key: ev.data() as usize,
})
}
@ -540,7 +529,6 @@ mod sys {
use crate::sys::event::{kevent_ts, kqueue, FilterFlag, KEvent};
use crate::sys::fcntl::{fcntl, FcntlArg};
use crate::sys::libc;
pub struct Reactor(RawFd);
impl Reactor {

View File

@ -53,9 +53,6 @@ pub mod unistd {
}
}
#[cfg(target_os = "linux")]
pub use nix::Error;
#[cfg(unix)]
pub mod fcntl {
use super::check_err;
@ -153,7 +150,7 @@ pub mod event {
#[allow(non_camel_case_types)]
type type_of_data = libc::int64_t;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct KEvent(libc::kevent);
@ -244,13 +241,103 @@ pub mod event {
}
}
#[cfg(unix)]
pub use libc;
#[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))]
/// Epoll.
pub mod epoll {
pub use nix::sys::epoll::{
epoll_create1, epoll_ctl, epoll_wait, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
};
use super::check_err;
use std::os::unix::io::RawFd;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(i32)]
pub enum EpollOp {
EpollCtlAdd = libc::EPOLL_CTL_ADD,
EpollCtlDel = libc::EPOLL_CTL_DEL,
EpollCtlMod = libc::EPOLL_CTL_MOD,
}
pub type EpollFlags = libc::c_int;
pub fn epoll_create1() -> Result<RawFd, std::io::Error> {
// 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 epoll_create1_flag = libc::O_CLOEXEC;
#[cfg(not(target_os = "android"))]
let epoll_create1_flag = libc::EPOLL_CLOEXEC;
let res = unsafe { libc::epoll_create1(epoll_create1_flag) };
check_err(res)
}
pub fn epoll_ctl<'a, T>(
epfd: RawFd,
op: EpollOp,
fd: RawFd,
event: T,
) -> Result<(), std::io::Error>
where
T: Into<Option<&'a mut EpollEvent>>,
{
let mut event: Option<&mut EpollEvent> = event.into();
if event.is_none() && op != EpollOp::EpollCtlDel {
Err(std::io::Error::from_raw_os_error(libc::EINVAL))
} else {
let res = unsafe {
if let Some(ref mut event) = event {
libc::epoll_ctl(epfd, op as libc::c_int, fd, &mut event.event)
} else {
libc::epoll_ctl(epfd, op as libc::c_int, fd, std::ptr::null_mut())
}
};
check_err(res).map(drop)
}
}
pub fn epoll_wait(
epfd: RawFd,
events: &mut [EpollEvent],
timeout_ms: isize,
) -> Result<usize, std::io::Error> {
let res = unsafe {
libc::epoll_wait(
epfd,
events.as_mut_ptr() as *mut libc::epoll_event,
events.len() as libc::c_int,
timeout_ms as libc::c_int,
)
};
check_err(res).map(|r| r as usize)
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct EpollEvent {
event: libc::epoll_event,
}
impl EpollEvent {
pub fn new(events: EpollFlags, data: u64) -> Self {
EpollEvent {
event: libc::epoll_event {
events: events as u32,
u64: data,
},
}
}
pub fn empty() -> Self {
unsafe { std::mem::zeroed::<EpollEvent>() }
}
pub fn events(&self) -> EpollFlags {
self.event.events as libc::c_int
}
pub fn data(&self) -> u64 {
self.event.u64
}
}
}