use std::marker::PhantomData;
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::{io, mem, ptr};
use crate::kqueue::{Completions, Shared, Submissions, cq};
use crate::syscall;
#[derive(Debug, Clone)]
pub(crate) struct Config<'r> {
max_events: u32,
max_change_list_size: u32,
_unused: PhantomData<&'r ()>,
}
impl<'r> Config<'r> {
pub(crate) const fn new() -> Config<'r> {
Config {
max_events: 64,
max_change_list_size: 32,
_unused: PhantomData,
}
}
}
impl<'r> crate::Config<'r> {
pub const fn max_events(mut self, max_events: u32) -> Self {
self.sys.max_events = max_events;
self
}
pub const fn max_change_list_size(mut self, max: u32) -> Self {
self.sys.max_change_list_size = max;
self
}
pub(crate) fn build_sys(self) -> io::Result<(Completions, Submissions)> {
debug_assert!(
self.sys.max_events >= self.sys.max_change_list_size,
"a10::kqueue::Config: max_change_list_size larger than max_events"
);
let kq = unsafe { OwnedFd::from_raw_fd(syscall!(kqueue())?) };
let kq_fd = kq.as_raw_fd();
syscall!(fcntl(kq_fd, libc::F_SETFD, libc::FD_CLOEXEC))?;
let mut kevent = libc::kevent {
ident: 0,
filter: libc::EVFILT_USER,
flags: libc::EV_ADD | libc::EV_CLEAR | libc::EV_RECEIPT,
udata: cq::WAKE_USER_DATA,
..unsafe { mem::zeroed() }
};
syscall!(kevent(
kq_fd,
&raw const kevent,
1,
&raw mut kevent,
1,
ptr::null()
))?;
if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
return Err(io::Error::from_raw_os_error(kevent.data as i32));
}
let shared = Shared {
max_change_list_size: self.sys.max_change_list_size,
change_list: Mutex::new(Vec::new()),
is_polling: AtomicBool::new(false),
kq,
};
let submissions = Submissions::new(shared);
let completions = Completions::new(self.sys.max_events);
Ok((completions, submissions))
}
}