use std::io;
use std::os::fd::RawFd;
use std::sync::Arc;
#[derive(Clone, Copy)]
pub(crate) struct WakeFd {
fd: RawFd,
}
impl WakeFd {
pub(crate) fn from_raw_fd(fd: RawFd) -> Self {
WakeFd { fd }
}
#[allow(dead_code)]
pub(crate) fn as_raw_fd(&self) -> RawFd {
self.fd
}
pub(crate) fn wake(&self) {
wake_fd(self.fd);
}
}
struct WakeFdInner {
fd: RawFd,
}
impl Drop for WakeFdInner {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
#[derive(Clone)]
pub struct WakeHandle {
inner: Arc<WakeFdInner>,
}
impl WakeHandle {
pub fn wake(&self) {
wake_fd(self.inner.fd);
}
pub(crate) fn as_wake_fd(&self) -> WakeFd {
WakeFd { fd: self.inner.fd }
}
}
fn wake_fd(fd: RawFd) {
#[cfg(has_io_uring)]
{
let val: u64 = 1;
unsafe {
libc::write(fd, &val as *const u64 as *const libc::c_void, 8);
}
}
#[cfg(not(has_io_uring))]
{
let val: u8 = 1;
unsafe {
libc::write(fd, &val as *const u8 as *const libc::c_void, 1);
}
}
}
#[cfg(has_io_uring)]
pub(crate) fn create_wake_fd() -> io::Result<(RawFd, WakeHandle)> {
let efd = unsafe { libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC) };
if efd < 0 {
return Err(io::Error::last_os_error());
}
Ok((
efd,
WakeHandle {
inner: Arc::new(WakeFdInner { fd: efd }),
},
))
}
#[cfg(not(has_io_uring))]
pub(crate) fn create_wake_fd() -> io::Result<(RawFd, WakeHandle)> {
let mut fds = [0i32; 2];
if unsafe { libc::pipe(fds.as_mut_ptr()) } < 0 {
return Err(io::Error::last_os_error());
}
let read_fd = fds[0];
let write_fd = fds[1];
for fd in &fds {
unsafe {
let flags = libc::fcntl(*fd, libc::F_GETFL);
libc::fcntl(*fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
let fd_flags = libc::fcntl(*fd, libc::F_GETFD);
libc::fcntl(*fd, libc::F_SETFD, fd_flags | libc::FD_CLOEXEC);
}
}
Ok((
read_fd,
WakeHandle {
inner: Arc::new(WakeFdInner { fd: write_fd }),
},
))
}