1use std::ffi::CString;
2use std::fs::File;
3use std::os::fd::AsFd;
4
5use nix::errno::Errno;
6use nix::unistd::{dup2_stderr, dup2_stdout};
7
8use crate::Error;
9
10pub fn redirect_output<T: AsFd>(fd: T) -> crate::Result<()> {
12 dup2_stdout(&fd).map_err(|e| Error::IO(e.to_string()))?;
13 dup2_stderr(&fd).map_err(|e| Error::IO(e.to_string()))?;
14 Ok(())
15}
16
17pub fn suppress_output() -> crate::Result<()> {
19 let f = File::options().write(true).open("/dev/null")?;
20 redirect_output(&f)?;
21 Ok(())
22}
23
24pub struct NamedSemaphore {
26 sem: *mut libc::sem_t,
27 size: u32,
28}
29
30impl NamedSemaphore {
31 pub fn new<S: AsRef<str>>(name: S, size: usize) -> crate::Result<Self> {
32 let name = CString::new(name.as_ref()).unwrap();
33 let size: u32 = size
34 .try_into()
35 .map_err(|_| Error::Base(format!("pool too large: {size}")))?;
36
37 let sem = unsafe { libc::sem_open(name.as_ptr(), libc::O_CREAT, 0o600, size) };
38 if !sem.is_null() {
39 unsafe { libc::sem_unlink(name.as_ptr()) };
40 Ok(Self { sem, size })
41 } else {
42 let err = Errno::last_raw();
43 Err(Error::Base(format!("sem_open() failed: {err}")))
44 }
45 }
46
47 pub fn acquire(&mut self) -> crate::Result<()> {
48 if unsafe { libc::sem_wait(self.sem) } == 0 {
49 Ok(())
50 } else {
51 let err = Errno::last_raw();
53 Err(Error::Base(format!("sem_wait() failed: {err}")))
54 } }
56
57 pub fn release(&mut self) -> crate::Result<()> {
58 if unsafe { libc::sem_post(self.sem) } == 0 {
59 Ok(())
60 } else {
61 let err = Errno::last_raw();
62 Err(Error::Base(format!("sem_post() failed: {err}")))
63 }
64 }
65
66 pub fn wait(&mut self) -> crate::Result<()> {
67 for _ in 0..self.size {
68 self.acquire()?;
69 }
70 Ok(())
71 }
72}
73
74impl Drop for NamedSemaphore {
75 fn drop(&mut self) {
76 unsafe {
77 libc::sem_close(self.sem);
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn semaphore() {
88 let size = u32::MAX.try_into().unwrap();
90 assert!(NamedSemaphore::new("test", size).is_err());
91
92 let size = i32::MAX.try_into().unwrap();
94 let mut sem = NamedSemaphore::new("test", size).unwrap();
95 assert!(sem.release().is_err());
97
98 sem.acquire().unwrap();
100 assert!(sem.release().is_ok());
101
102 let mut sem = NamedSemaphore::new("test", 10).unwrap();
104 sem.wait().unwrap();
105 }
106}