NetworkKVM/server/src/epoll.rs
2023-03-19 22:42:08 -04:00

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,
}
}