use std::ffi::CString;
use std::fs::File;
use std::os::fd::AsFd;
use nix::errno::Errno;
use nix::unistd::{dup2_stderr, dup2_stdout};
use crate::Error;
pub fn redirect_output<T: AsFd>(fd: T) -> crate::Result<()> {
dup2_stdout(&fd).map_err(|e| Error::IO(e.to_string()))?;
dup2_stderr(&fd).map_err(|e| Error::IO(e.to_string()))?;
Ok(())
}
pub fn suppress_output() -> crate::Result<()> {
let f = File::options().write(true).open("/dev/null")?;
redirect_output(&f)?;
Ok(())
}
pub struct NamedSemaphore {
sem: *mut libc::sem_t,
size: u32,
}
impl NamedSemaphore {
pub fn new<S: AsRef<str>>(name: S, size: usize) -> crate::Result<Self> {
let name = CString::new(name.as_ref()).unwrap();
let size: u32 = size
.try_into()
.map_err(|_| Error::Base(format!("pool too large: {size}")))?;
let sem = unsafe { libc::sem_open(name.as_ptr(), libc::O_CREAT, 0o600, size) };
if !sem.is_null() {
unsafe { libc::sem_unlink(name.as_ptr()) };
Ok(Self { sem, size })
} else {
let err = Errno::last_raw();
Err(Error::Base(format!("sem_open() failed: {err}")))
}
}
pub fn acquire(&mut self) -> crate::Result<()> {
if unsafe { libc::sem_wait(self.sem) } == 0 {
Ok(())
} else {
let err = Errno::last_raw();
Err(Error::Base(format!("sem_wait() failed: {err}")))
} }
pub fn release(&mut self) -> crate::Result<()> {
if unsafe { libc::sem_post(self.sem) } == 0 {
Ok(())
} else {
let err = Errno::last_raw();
Err(Error::Base(format!("sem_post() failed: {err}")))
}
}
pub fn wait(&mut self) -> crate::Result<()> {
for _ in 0..self.size {
self.acquire()?;
}
Ok(())
}
}
impl Drop for NamedSemaphore {
fn drop(&mut self) {
unsafe {
libc::sem_close(self.sem);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn semaphore() {
let size = u32::MAX.try_into().unwrap();
assert!(NamedSemaphore::new("test", size).is_err());
let size = i32::MAX.try_into().unwrap();
let mut sem = NamedSemaphore::new("test", size).unwrap();
assert!(sem.release().is_err());
sem.acquire().unwrap();
assert!(sem.release().is_ok());
let mut sem = NamedSemaphore::new("test", 10).unwrap();
sem.wait().unwrap();
}
}