use std::os::fd::AsRawFd as _;
use crate::{
EventSources,
Fd,
NTSYNC_MAGIC,
NtSync,
raw,
};
use derive_new::new;
use log::*;
use nix::{
errno::Errno,
ioctl_read,
ioctl_readwrite,
ioctl_write_ptr,
};
#[repr(C)]
#[derive(Debug, new, Default)]
#[new(visibility = "pub(crate)")]
pub struct SemaphoreStatus {
#[new(value = "max")]
pub count: u32,
max: u32,
}
impl SemaphoreStatus {
pub fn max(&self) -> u32 {
self.max
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Semaphore {
pub(crate) id: Fd,
}
unsafe impl Send for Semaphore {}
impl From<Semaphore> for EventSources {
fn from(val: Semaphore) -> Self {
EventSources::Semaphore(val)
}
}
impl Semaphore {
pub fn release(&self, mut amount: u32) -> crate::Result<u32> {
match unsafe { ntsync_sem_release(self.id, raw!(mut amount: u32)) } {
Ok(_) => Ok(amount),
Err(errno) => {
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)),
}
},
}
}
#[allow(unused)]
pub fn read(&self) -> crate::Result<SemaphoreStatus> {
let mut args = SemaphoreStatus::default();
match unsafe { ntsync_sem_read(self.id, raw!(mut args: SemaphoreStatus)) } {
Ok(_) => Ok(args),
Err(errno) => {
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)),
}
},
}
}
}
impl NtSync {
pub fn new_semaphore(&self, maximum: u32) -> crate::Result<Semaphore> {
let args = SemaphoreStatus::new(maximum.clamp(1, u32::MAX));
match unsafe { ntsync_create_sem(self.inner.handle.as_raw_fd(), raw!(const args: SemaphoreStatus)) } {
Ok(fd) => {
Ok(Semaphore {
id: fd,
})
},
Err(errno) => {
trace!(target: "ntsync", handle=self.inner.handle.as_raw_fd(), returncode=errno as i32 ;"Failed to create semaphore");
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_sem, NTSYNC_MAGIC, 0x80, SemaphoreStatus);
ioctl_read!(ntsync_sem_read, NTSYNC_MAGIC, 0x8B, SemaphoreStatus);
ioctl_readwrite!(ntsync_sem_release, NTSYNC_MAGIC, 0x81, u32);