106 lines
2.8 KiB
Rust
106 lines
2.8 KiB
Rust
use std::io;
|
|
use std::os::fd::RawFd;
|
|
|
|
use libc::epoll_event;
|
|
|
|
pub struct Epoll {
|
|
fd: RawFd,
|
|
pub events: Vec<epoll_event>,
|
|
}
|
|
|
|
const READ_FLAGS: i32 = libc::EPOLLONESHOT | libc::EPOLLIN;
|
|
const WRITE_FLAGS: i32 = libc::EPOLLONESHOT | libc::EPOLLOUT;
|
|
|
|
const EVENTS_CAPACITY: usize = 1024;
|
|
const WAIT_MAX_EVENTS: i32 = 1024;
|
|
const WAIT_TIMEOUT: i32 = 1000;
|
|
|
|
impl Epoll {
|
|
pub fn create() -> io::Result<Self> {
|
|
match epoll_create() {
|
|
Ok(fd) => Ok(Epoll {
|
|
fd,
|
|
events: Vec::with_capacity(EVENTS_CAPACITY),
|
|
}),
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
pub fn add_read_interest(&self, fd: RawFd, key: u64) -> io::Result<()> {
|
|
add_interest(self.fd, fd, listener_read_event(key))
|
|
}
|
|
|
|
pub fn modify_read_interest(&self, fd: RawFd, key: u64) -> io::Result<()> {
|
|
modify_interest(self.fd, fd, listener_read_event(key))
|
|
}
|
|
|
|
pub fn wait(&mut self) -> io::Result<()> {
|
|
self.events.clear();
|
|
match epoll_wait(self.fd, &mut self.events, WAIT_MAX_EVENTS, WAIT_TIMEOUT) {
|
|
Ok(res) => {
|
|
// safe as long as the kernel does nothing wrong - copied from mio
|
|
unsafe { self.events.set_len(res) }
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn is_read_event(event: u32) -> bool {
|
|
event as i32 & libc::EPOLLIN == libc::EPOLLIN
|
|
}
|
|
|
|
pub fn is_write_event(event: u32) -> bool {
|
|
event as i32 & libc::EPOLLOUT == libc::EPOLLOUT
|
|
}
|
|
|
|
macro_rules! syscall {
|
|
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
|
|
let res = unsafe { libc::$fn($($arg, )*) };
|
|
if res == -1 {
|
|
Err(std::io::Error::last_os_error())
|
|
} else {
|
|
Ok(res)
|
|
}
|
|
}};
|
|
}
|
|
|
|
fn epoll_create() -> io::Result<RawFd> {
|
|
let fd = syscall!(epoll_create1(0))?;
|
|
if let Ok(flags) = syscall!(fcntl(fd, libc::F_GETFD)) {
|
|
let _ = syscall!(fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC));
|
|
}
|
|
|
|
Ok(fd)
|
|
}
|
|
|
|
fn epoll_wait(epoll_fd: RawFd, events: &mut Vec<epoll_event>, max_events: i32, timeout: i32) -> io::Result<usize> {
|
|
match syscall!(epoll_wait(
|
|
epoll_fd,
|
|
events.as_mut_ptr() as *mut libc::epoll_event,
|
|
max_events,
|
|
timeout as libc::c_int
|
|
)) {
|
|
Ok(v) => Ok(v as usize),
|
|
Err(e) => Err(e)
|
|
}
|
|
}
|
|
|
|
fn add_interest(epoll_fd: RawFd, fd: RawFd, mut event: epoll_event) -> io::Result<()> {
|
|
syscall!(epoll_ctl(epoll_fd, libc::EPOLL_CTL_ADD, fd, &mut event))?;
|
|
Ok(())
|
|
}
|
|
|
|
fn modify_interest(epoll_fd: RawFd, fd: RawFd, mut event: epoll_event) -> io::Result<()> {
|
|
syscall!(epoll_ctl(epoll_fd, libc::EPOLL_CTL_MOD, fd, &mut event))?;
|
|
Ok(())
|
|
}
|
|
|
|
fn listener_read_event(key: u64) -> epoll_event {
|
|
epoll_event {
|
|
events: READ_FLAGS as u32,
|
|
u64: key,
|
|
}
|
|
}
|