use std::{
io,
os::fd::AsRawFd as _,
};
use crate::{
Error,
EventSources,
Fd,
NTSYNC_MAGIC,
NTSyncObjects,
NtSync,
Sealed,
cold_path,
raw,
};
use derive_new::new;
use log::*;
use nix::{
errno::Errno,
ioctl_read,
ioctl_readwrite,
ioctl_write_ptr,
libc,
};
#[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 {}
unsafe impl Sync 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) => {
cold_path();
match errno {
Errno::EOVERFLOW => Err(crate::Error::SemaphoreOverflow),
Errno::EBADF => Err(crate::Error::AlreadyClosed),
other => {
cold_path();
Err(crate::Error::Unknown(other as i32))
},
}
},
}
}
}
impl Sealed for Semaphore {}
impl NTSyncObjects for Semaphore {
type Status = SemaphoreStatus;
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 Semaphore");
Err(Error::AlreadyClosed)
},
Errno::EINTR => {
trace!(target: "ntsync", handle=self.id; "While closing the Semaphore an interrupt occured");
Err(Error::Interrupt)
},
Errno::EIO => {
trace!(target: "ntsync", handle=self.id; "While closing the Semaphore an IOError occured");
Err(Error::IOError(io::Error::from_raw_os_error(Errno::EIO as i32)))
},
errno => {
cold_path();
trace!(target: "ntsync", handle=self.id; "Unexpected error while closing the semaphore: {errno}");
Err(Error::Unknown(errno as i32))
},
};
}
Ok(())
}
#[allow(unused)]
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::EBADF) => {
cold_path();
Err(crate::Error::AlreadyClosed)
},
Err(errno) => {
cold_path();
Err(crate::Error::Unknown(errno 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),
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);