classic_sync/
semaphore.rs

1use std::time::Duration;
2
3use crate::binding::{self, SemPtr, c_destroy_semaphore,c_p_semaphore_timed, c_init_semaphore, c_p_semaphore, c_v_semaphore, SEM_E_TIMEOUT, SEM_P_V_ON_UNINIT, SEM_INIT_DOUBLE_INIT};
4
5#[derive(Debug)]
6pub struct SemaphoreError {
7    code:i32
8}
9
10/// Wrapper of sem_t in c. Providing Semaphore access without mut access. It is super easy to share!
11/// 
12/// Example:
13/// ```
14/// use std::sync::Arc;
15/// use std::time::Duration;
16/// use std::thread;
17/// use classic_sync::semaphore::Semaphore;
18/// let sem = Semaphore::new(3); // allows 3 concurrent access
19/// let arc_sem = Arc::new(sem);
20/// for i in 0..3 {
21///     let sem_copy = Arc::clone(&arc_sem);
22///     let tid = i;
23///     thread::spawn(move || {
24///         sem_copy.p();
25///         println!("Now I am granted access. I should have 2 other siblings has the access at the same time!");
26///         std::thread::sleep(Duration::from_secs(3));
27///         // Other people can't acquire the lock even when I am sleeping.
28///         sem_copy.v(); // You have to manually unlock it to release the lock
29///     });
30/// }
31/// ```
32impl SemaphoreError {
33    pub fn code(&self) -> i32 {
34        return self.code;
35    }
36
37    pub fn is_timeout(&self) -> bool {
38        return self.code == SEM_E_TIMEOUT;
39    }
40
41    pub fn msg(&self)->String {
42        if self.code == SEM_P_V_ON_UNINIT {
43            "Use of uninitialized SEMAPHORE".into()
44        } else if self.code == SEM_INIT_DOUBLE_INIT {
45            "Can't double init SEMAPHORE".into()
46        } else if self.code == SEM_E_TIMEOUT {
47            "Semaphore wait timed out".into()
48        } else {
49            format!("SyscallError code: {}", self.code)  
50        }
51    }
52}
53impl std::fmt::Display for SemaphoreError {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(f, "SemaphoreError code :{}, message:{}", self.code, self.msg())
56    }
57}
58
59impl std::error::Error for SemaphoreError {
60}
61
62type SemaphoreResult<T> = Result<T, SemaphoreError>;
63
64impl SemPtr {
65    fn init(&self, count: i32)-> i32 {
66        unsafe {
67            return c_init_semaphore(self, count);
68        }
69    }
70    fn close(&self) -> i32 {
71        unsafe {
72            return c_destroy_semaphore(self);
73        }
74    }
75
76    fn p(&self) -> i32 {
77        unsafe {
78            return c_p_semaphore(self);
79        }
80    }
81
82    fn p_timeout(&self, nanos:i64) -> i32 {
83        unsafe {
84            return c_p_semaphore_timed(self, nanos);
85        }
86    }
87    fn v(&self) -> i32 {
88        unsafe {
89            return c_v_semaphore(self);
90        }
91    }
92}
93
94#[derive(Debug)]
95pub struct Semaphore {
96    ptr: SemPtr,
97}
98
99fn test<T>(what:T) where
100T: Send {
101
102}
103impl Semaphore {
104    pub fn new(count:i32) -> Semaphore {
105        let ptr = SemPtr {
106            sem_ptr: 0,
107        };
108        let result = ptr.init(count);
109        if result != 0 {
110            panic!("Semaphore init error {result}");
111        }
112        return Semaphore {
113            ptr
114        };
115    }
116
117    pub fn v(&self) {
118        let result = self.ptr.v();
119        if result == 0 {
120            return;
121        }
122        panic!("v() operation on semaphore can't fail");
123    }
124
125    pub fn p_timeout(&self, duration:Duration) -> bool {
126        let nanos = duration.as_nanos();
127        let result = self.ptr.p_timeout(nanos as i64);
128        if result == 0 {
129            return true;
130        }
131        return false;
132    }
133
134    pub fn p(&self) {
135        let result = self.ptr.p();
136
137        if result != 0 {
138            panic!("p() operation didn't work");
139        }
140    }
141}
142
143impl Drop for Semaphore {
144    fn drop(&mut self) {
145        self.ptr.close();
146    }
147}