use std::{io, result};
use utils::eventfd::EventFd;
#[cfg(unix)]
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
pub struct ExitHandle {
#[cfg(unix)]
write_fd: OwnedFd,
#[cfg(target_os = "windows")]
event: EventFd,
}
impl ExitHandle {
#[cfg(unix)]
pub(crate) fn from_event_fd(evt: &EventFd) -> result::Result<Self, io::Error> {
#[cfg(target_os = "linux")]
let raw_fd = evt.as_raw_fd();
#[cfg(target_os = "macos")]
let raw_fd = evt.get_write_fd();
let fd = unsafe { libc::dup(raw_fd) };
if fd < 0 {
return Err(io::Error::last_os_error());
}
let write_fd = unsafe { OwnedFd::from_raw_fd(fd) };
Ok(Self { write_fd })
}
#[cfg(target_os = "windows")]
pub(crate) fn from_event_fd(evt: &EventFd) -> result::Result<Self, io::Error> {
Ok(Self {
event: evt.try_clone()?,
})
}
#[cfg(unix)]
pub fn trigger(&self) {
let val: u64 = 1;
let _ = unsafe {
libc::write(
self.write_fd.as_raw_fd(),
&val as *const u64 as *const libc::c_void,
std::mem::size_of::<u64>(),
)
};
}
#[cfg(target_os = "windows")]
pub fn trigger(&self) {
let _ = self.event.write(1);
}
}
impl Clone for ExitHandle {
#[cfg(unix)]
fn clone(&self) -> Self {
let fd = unsafe { libc::dup(self.write_fd.as_raw_fd()) };
assert!(fd >= 0, "Failed to dup ExitHandle fd");
let write_fd = unsafe { OwnedFd::from_raw_fd(fd) };
Self { write_fd }
}
#[cfg(target_os = "windows")]
fn clone(&self) -> Self {
Self {
event: self
.event
.try_clone()
.expect("Failed to clone ExitHandle event"),
}
}
}
unsafe impl Send for ExitHandle {}
unsafe impl Sync for ExitHandle {}