use std::os::fd::AsRawFd as _;
use derive_new::new;
use log::*;
use nix::{
errno::Errno,
ioctl_read,
ioctl_readwrite,
ioctl_write_ptr,
};
use crate::{
EventSources,
Fd,
NTSYNC_MAGIC,
NtSync,
OwnerId,
raw,
};
#[repr(C)]
#[derive(Debug, new, Default)]
#[new(visibility = "pub(crate)")]
pub struct MutexStatus {
owner: OwnerId,
#[new(value = "0")]
count: u32,
}
impl MutexStatus {
pub fn owner(&self) -> Option<OwnerId> {
if self.owner.0 == 0 {
return None;
}
Some(self.owner)
}
pub fn depth(&self) -> Option<u32> {
if self.count != 0 {
Some(self.count)
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Mutex {
pub(crate) id: Fd,
}
unsafe impl Send for Mutex {}
impl From<Mutex> for EventSources {
fn from(value: Mutex) -> EventSources {
EventSources::Mutex(value)
}
}
impl Mutex {
pub fn unlock(&self, owner: OwnerId) -> crate::Result<()> {
let mut args = MutexStatus::new(owner);
match unsafe { ntsync_mutex_unlock(self.id, raw!(mut args: MutexStatus)) } {
Ok(_) => Ok(()),
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<MutexStatus> {
let mut args = MutexStatus::default();
match unsafe { ntsync_mutex_read(self.id, raw!(mut args: MutexStatus)) } {
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)),
}
},
}
}
pub fn kill(&self, owner: OwnerId) -> crate::Result<()> {
let id = owner.0;
match unsafe { ntsync_mutex_kill(self.id, raw!(const id: u32)) } {
Ok(_) => {
error!(target: "ntsync", "Mutex {} was killed.", self.id);
Ok(())
},
Err(errno) => {
error!(target: "ntsync", "Wanted to kill Mutex {}, but failed", self.id);
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_mutex(&self) -> crate::Result<Mutex> {
let args = MutexStatus::default();
match unsafe { ntsync_create_mutex(self.inner.handle.as_raw_fd(), raw!(const args: MutexStatus)) } {
Ok(fd) => {
Ok(Mutex {
id: fd,
})
},
Err(errno) => {
trace!(target: "ntsync", handle=self.inner.handle.as_raw_fd(), returncode=errno as i32 ;"Failed to create Mutex");
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_mutex, NTSYNC_MAGIC, 0x84, MutexStatus);
ioctl_readwrite!(ntsync_mutex_unlock, NTSYNC_MAGIC, 0x85, MutexStatus);
ioctl_write_ptr!(ntsync_mutex_kill, NTSYNC_MAGIC, 0x86, u32);
ioctl_read!(ntsync_mutex_read, NTSYNC_MAGIC, 0x8C, MutexStatus);