use std::{
io::Error as IOError,
os::fd::AsRawFd as _,
};
use derive_new::new;
use nix::{
errno::Errno,
ioctl_read,
ioctl_write_ptr,
libc,
};
use crate::{
Error,
EventSources,
Fd,
NTSYNC_MAGIC,
NTSyncObjects,
NtSync,
Sealed,
cold_path,
raw,
};
use log::*;
#[repr(C)]
#[derive(Debug, new, Default)]
#[new(visibility = "pub(crate)")]
pub struct EventStatus {
manual: u32,
signaled: u32,
}
impl EventStatus {
pub fn manual_reset(&self) -> bool {
self.manual == 1
}
pub fn signaled(&self) -> bool {
self.signaled == 1
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Event {
pub(crate) id: Fd,
}
impl Event {
pub fn signal(&self) -> crate::Result<bool> {
let mut state: u32 = 0;
match unsafe { ntsync_event_set(self.id, raw!(mut state: u32)) } {
Ok(_) => Ok(state != 0),
Err(Errno::EINVAL) => Err(crate::Error::InvalidValue),
Err(Errno::EBADF) => Err(Error::AlreadyClosed),
Err(errno) => {
cold_path();
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to signal event");
Err(crate::Error::Unknown(errno as i32))
},
}
}
pub fn reset(&self) -> crate::Result<bool> {
let mut state: u32 = 0;
match unsafe { ntsync_event_reset(self.id, raw!(mut state: u32)) } {
Ok(_) => Ok(state != 0),
Err(Errno::EINVAL) => Err(crate::Error::InvalidValue),
Err(Errno::EBADF) => Err(Error::AlreadyClosed),
Err(errno) => {
cold_path();
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to reset event");
Err(crate::Error::Unknown(errno as i32))
},
}
}
pub fn pulse(&self) -> crate::Result<bool> {
let mut state: u32 = 0;
match unsafe { ntsync_event_pulse(self.id, raw!(mut state: u32)) } {
Ok(_) => Ok(state != 0),
Err(Errno::EINVAL) => Err(crate::Error::InvalidValue),
Err(Errno::EBADF) => Err(Error::AlreadyClosed),
Err(errno) => {
cold_path();
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to pulse event");
Err(crate::Error::Unknown(errno as i32))
},
}
}
pub fn status(&self) -> crate::Result<EventStatus> {
let mut args = EventStatus::default();
match unsafe { ntsync_event_read(self.id, raw!(mut args: EventStatus)) } {
Ok(_) => Ok(args),
Err(Errno::EBADF) => {
cold_path();
trace!(target: "ntsync", handle=self.id ;"Event is already closed");
Err(crate::Error::AlreadyClosed)
},
Err(errno) => {
cold_path();
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to query event");
Err(crate::Error::Unknown(errno as i32))
},
}
}
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl From<Event> for EventSources {
fn from(val: Event) -> Self {
EventSources::Event(val)
}
}
impl NtSync {
pub fn new_event(&self, signaled: bool, manual: bool) -> crate::Result<Event> {
let args = EventStatus::new(signaled as u32, manual as u32);
match unsafe { ntsync_create_event(self.inner.handle.as_raw_fd(), raw!(const args: EventStatus)) } {
Ok(fd) => {
Ok(Event {
id: fd,
})
},
Err(errno) => {
cold_path();
trace!(target: "ntsync", handle=self.inner.handle.as_raw_fd(), returncode=errno as i32 ;"Failed to create event");
Err(crate::Error::Unknown(errno as i32))
},
}
}
}
impl Sealed for Event {}
impl NTSyncObjects for Event {
type Status = EventStatus;
fn delete(self) -> crate::Result<()> {
if unsafe { libc::close(self.id) } == -1 {
cold_path();
return match Errno::last() {
Errno::EBADF => {
trace!(target: "ntsync", handle=self.id; "tried to double close an event");
Err(Error::AlreadyClosed)
},
Errno::EINTR => {
trace!(target: "ntsync", handle=self.id; "While closing the Event an interrupt occured");
Err(Error::Interrupt)
},
Errno::EIO => {
trace!(target: "ntsync", handle=self.id; "While closing the Event an IOError occured");
Err(Error::IOError(IOError::from_raw_os_error(Errno::EIO as i32)))
},
errno => {
cold_path();
trace!(target: "ntsync", handle=self.id; "Unexpected error while closing the event: {errno}");
Err(Error::Unknown(errno as i32))
},
};
}
Ok(())
}
fn read(&self) -> crate::Result<Self::Status> {
self.status()
}
}
ioctl_write_ptr!(ntsync_create_event, NTSYNC_MAGIC, 0x87, EventStatus);
ioctl_read!(ntsync_event_set, NTSYNC_MAGIC, 0x88, u32);
ioctl_read!(ntsync_event_reset, NTSYNC_MAGIC, 0x89, u32);
ioctl_read!(ntsync_event_pulse, NTSYNC_MAGIC, 0x8A, u32);
ioctl_read!(ntsync_event_read, NTSYNC_MAGIC, 0x8D, EventStatus);