Hallo,
I am trying to implement an epoll loop like I would do it in C/C++ but I get problems in sharing the epollfd.
epoll::wait should run in an own thread so that I can add,del,mod filedescriptors from outside and close the epollfd from outside.
I want to use epoll::wait with an infinite timeout. So this call is blocking. It would be released if the epollfd is closed.
If I encapsulate the epollfd into an Arc::Mutex it would block on epoll::wait and I got a deadlock on add,del,mod filedescriptors and on clonsing the epollfd from outside.
How could I solve this in Rust?
Thanks
use std::{thread::JoinHandle, sync::{atomic::{AtomicBool, Ordering, AtomicI32}, Arc}};
struct Io {
epfd: i32,
hdl: Option<JoinHandle<()>>,
is_running: Arc<AtomicBool>,
}
impl Drop for Io {
fn drop(&mut self) {
println!("1");
self.is_running.store(false, Ordering::Relaxed);
println!("2");
//I think it is not working because this is not the epollfd that is used in epoll::wait
epoll::close(self.epfd).unwrap();
println!("3");
if let Some(hdl) = self.hdl.take() {
hdl.join().unwrap();
}
println!("drop");
}
}
impl Io {
pub fn new() -> std::io::Result<Self> {
let epfd = epoll::create(false)?;
Ok(Self {
epfd,
hdl: None,
is_running: Arc::new(AtomicBool::new(false)),
})
}
//Example
pub fn add(&self, fd: i32) {
epoll::ctl(
self.epfd,
epoll::ControlOptions::EPOLL_CTL_ADD,
fd,
epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLRDHUP | epoll::Events::EPOLLHUP | epoll::Events::EPOLLERR,
0)
).unwrap();
}
fn start(&mut self) {
self.is_running.store(true, Ordering::Relaxed);
//How to share epfd properly?
let epfd = self.epfd;
let is_running = Arc::clone(&self.is_running);
self.hdl = Some(std::thread::spawn(move || {
while is_running.load(Ordering::Relaxed) {
println!("before epoll");
let mut events = [epoll::Event::new(epoll::Events::empty(), 0); 10];
let event_count = epoll::wait(epfd, -1, &mut events).unwrap();
println!("after epoll");
}
}));
}
}