#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(clippy::panic)]
#![forbid(clippy::unimplemented)]
#![warn(missing_docs)]
#![doc = include_str!("../README.md")]
use bitflags::bitflags;
use derive_new::new;
use log::*;
use nix::libc::c_int;
use std::{
fmt::Display,
fs::{
File,
exists,
},
result,
sync::Arc,
};
mod error;
mod event;
#[cfg(mutex)]
#[cfg_attr(docsrs, doc(cfg(feature = "mutex")))]
mod mutex;
#[cfg(semaphore)]
#[cfg_attr(docsrs, doc(cfg(feature = "semaphore")))]
mod semaphore;
mod wait;
pub use crate::error::Error;
#[cfg(semaphore)]
#[cfg_attr(docsrs, doc(cfg(feature = "semaphore")))]
pub use crate::semaphore::{
Semaphore,
SemaphoreStatus,
};
pub use event::{
Event,
EventStatus,
};
#[cfg(mutex)]
#[cfg_attr(docsrs, doc(cfg(feature = "mutex")))]
pub use mutex::{
Mutex,
MutexStatus,
};
const DEVICE: &str = "/dev/ntsync";
const NTSYNC_MAGIC: u8 = b'N';
type Fd = c_int;
pub(crate) type Result<T> = result::Result<T, Error>;
macro_rules! raw {
(mut $var:ident : $type:ty) => {
&mut $var as *mut $type
};
(const $var:ident : $type:ty) => {
&$var as *const $type
};
}
pub(crate) use raw;
#[inline(always)]
#[cold]
pub(crate) fn cold_path() {}
bitflags! {
#[derive(Debug, Default)]
pub struct NtSyncFlags: u32 {
const WaitRealtime = 0x1;
}
}
#[repr(transparent)]
#[derive(Debug, new, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Default)]
pub struct OwnerId(u32);
#[cfg(random)]
#[cfg_attr(docsrs, doc(cfg(feature = "semaphore")))]
impl OwnerId {
pub fn random() -> Self {
OwnerId(rand::random::<u32>().clamp(1, u32::MAX))
}
}
impl Display for OwnerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug)]
#[doc(hidden)]
struct NtSyncInner {
handle: File,
}
#[derive(Debug)]
pub struct NtSync {
inner: Arc<NtSyncInner>,
}
impl NtSync {
pub fn new() -> crate::Result<Self> {
match exists(DEVICE) {
Ok(true) => {},
Ok(false) => return Err(Error::NotExist),
Err(error) => {
cold_path();
return Err(Error::IOError(error));
},
}
match File::open(DEVICE) {
Ok(file) => {
Ok(NtSync {
inner: Arc::new(NtSyncInner {
handle: file,
}),
})
},
Err(error) => {
cold_path();
trace!(target: "ntsync","Failed to open ntsync device: {error}");
Err(Error::IOError(error))
},
}
}
}
unsafe impl Send for NtSync {}
unsafe impl Sync for NtSync {}
impl Clone for NtSync {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum EventSources {
#[cfg(mutex)]
#[cfg_attr(docsrs, doc(cfg(feature = "mutex")))]
Mutex(mutex::Mutex),
#[cfg(semaphore)]
#[cfg_attr(docsrs, doc(cfg(feature = "semaphore")))]
Semaphore(semaphore::Semaphore),
Event(event::Event),
}
impl EventSources {
#[cfg_attr(feature = "mutex", doc = "- [Mutex](crate::mutex::Mutex) are unlocked.")]
#[cfg_attr(
feature = "semaphore",
doc = "- [Semaphore](crate::semaphore::Semaphore) are released with an amount of 1."
)]
#[doc = "- [Event](crate::event::Event) are reset."]
pub fn free(&self, _owner: OwnerId) -> Result<()> {
match self {
#[cfg(mutex)]
EventSources::Mutex(mutex) => {
mutex.unlock(_owner)?;
},
#[cfg(semaphore)]
EventSources::Semaphore(semaphore) => {
semaphore.release(1)?;
},
EventSources::Event(event) => {
event.reset()?;
},
};
Ok(())
}
}
trait Sealed {}
#[allow(private_bounds)]
pub trait NTSyncObjects: Sealed + Into<EventSources> + Clone + Copy {
type Status;
fn delete(self) -> Result<()>;
fn read(&self) -> Result<Self::Status>;
}