use std::os::fd::AsRawFd as _;
use derive_new::new;
use nix::{
errno::Errno,
ioctl_read,
ioctl_write_ptr,
};
use crate::{
EventSources,
Fd,
NTSYNC_MAGIC,
NtSync,
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) => {
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to signal event");
match errno {
Errno::EINVAL => Err(crate::Error::InvalidValue),
Errno::EPERM => Err(crate::Error::PermissionDenied),
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EINTR => Err(crate::Error::Interrupt),
Errno::EOWNERDEAD => Err(crate::Error::OwnerDead),
Errno::ETIMEDOUT => Err(crate::Error::Timeout),
other => Err(crate::Error::Unknown(other 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) => {
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to reset event");
match errno {
Errno::EINVAL => Err(crate::Error::InvalidValue),
Errno::EPERM => Err(crate::Error::PermissionDenied),
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EINTR => Err(crate::Error::Interrupt),
Errno::EOWNERDEAD => Err(crate::Error::OwnerDead),
Errno::ETIMEDOUT => Err(crate::Error::Timeout),
other => Err(crate::Error::Unknown(other 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) => {
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to pulse event");
match errno {
Errno::EINVAL => Err(crate::Error::InvalidValue),
Errno::EPERM => Err(crate::Error::PermissionDenied),
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EINTR => Err(crate::Error::Interrupt),
Errno::EOWNERDEAD => Err(crate::Error::OwnerDead),
Errno::ETIMEDOUT => Err(crate::Error::Timeout),
other => Err(crate::Error::Unknown(other 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) => {
trace!(target: "ntsync", handle=self.id, returncode=errno as i32 ;"Failed to query event");
match errno {
Errno::EINVAL => Err(crate::Error::InvalidValue),
Errno::EPERM => Err(crate::Error::PermissionDenied),
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EINTR => Err(crate::Error::Interrupt),
Errno::EOWNERDEAD => Err(crate::Error::OwnerDead),
Errno::ETIMEDOUT => Err(crate::Error::Timeout),
other => Err(crate::Error::Unknown(other as i32)),
}
},
}
}
}
unsafe impl Send 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) => {
trace!(target: "ntsync", handle=self.inner.handle.as_raw_fd(), returncode=errno as i32 ;"Failed to create event");
match errno {
Errno::EINVAL => Err(crate::Error::InvalidValue),
Errno::EPERM => Err(crate::Error::PermissionDenied),
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EINTR => Err(crate::Error::Interrupt),
Errno::EOWNERDEAD => Err(crate::Error::OwnerDead),
Errno::ETIMEDOUT => Err(crate::Error::Timeout),
other => Err(crate::Error::Unknown(other as i32)),
}
},
}
}
}
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);