1pub mod condvar;
37pub mod futex;
38pub mod raw_mutex;
39pub mod raw_rwlock;
40
41pub use condvar::{Condvar, WaitTimeoutResult};
42pub use raw_mutex::NoxuRawMutex;
43pub use raw_rwlock::NoxuRawRwLock;
44
45pub use lock_api;
47
48pub type Mutex<T> = lock_api::Mutex<NoxuRawMutex, T>;
56
57pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, NoxuRawMutex, T>;
59
60pub type RawMutex = NoxuRawMutex;
65
66pub type RwLockReadGuard<'a, T> =
72 lock_api::RwLockReadGuard<'a, NoxuRawRwLock, T>;
73
74pub type RwLockWriteGuard<'a, T> =
76 lock_api::RwLockWriteGuard<'a, NoxuRawRwLock, T>;
77
78pub struct RwLock<T>(lock_api::RwLock<NoxuRawRwLock, T>);
88
89impl<T> RwLock<T> {
90 #[inline]
92 pub fn new(val: T) -> Self {
93 RwLock(lock_api::RwLock::new(val))
94 }
95
96 #[inline]
98 pub fn read(&self) -> RwLockReadGuard<'_, T> {
99 self.0.read()
100 }
101
102 #[inline]
104 pub fn write(&self) -> RwLockWriteGuard<'_, T> {
105 self.0.write()
106 }
107
108 #[inline]
110 pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
111 self.0.try_read()
112 }
113
114 #[inline]
116 pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
117 self.0.try_write()
118 }
119
120 #[inline]
122 pub fn try_read_for(
123 &self,
124 timeout: std::time::Duration,
125 ) -> Option<RwLockReadGuard<'_, T>> {
126 self.0.try_read_for(timeout)
127 }
128
129 #[inline]
131 pub fn try_write_for(
132 &self,
133 timeout: std::time::Duration,
134 ) -> Option<RwLockWriteGuard<'_, T>> {
135 self.0.try_write_for(timeout)
136 }
137
138 #[inline]
140 pub fn is_locked(&self) -> bool {
141 self.0.is_locked()
142 }
143
144 #[inline]
146 pub fn is_locked_exclusive(&self) -> bool {
147 unsafe { self.0.raw().is_write_locked() }
149 }
150
151 #[inline]
153 pub fn get_n_waiters(&self) -> usize {
154 unsafe { self.0.raw().get_n_waiters() }
155 }
156
157 #[inline]
159 pub fn reader_count(&self) -> u32 {
160 unsafe { self.0.raw().reader_count() }
161 }
162
163 #[inline]
165 pub fn raw(&self) -> &NoxuRawRwLock {
166 unsafe { self.0.raw() }
167 }
168}
169
170#[cfg(test)]
175mod tests {
176 use super::*;
177 use std::sync::Arc;
178 use std::time::Duration;
179
180 #[test]
183 fn mutex_basic() {
184 let m = Mutex::new(0i32);
185 *m.lock() = 42;
186 assert_eq!(*m.lock(), 42);
187 }
188
189 #[test]
190 fn mutex_try_lock() {
191 let m = Arc::new(Mutex::new(()));
192 let g = m.lock();
193 let m2 = m.clone();
194 let failed =
195 std::thread::spawn(move || m2.try_lock().is_none()).join().unwrap();
196 assert!(failed);
197 drop(g);
198 assert!(m.try_lock().is_some());
199 }
200
201 #[test]
202 fn mutex_try_lock_for_timeout() {
203 let m = Arc::new(Mutex::new(()));
204 let g = m.lock();
205 let m2 = m.clone();
206 let timed_out = std::thread::spawn(move || {
207 m2.try_lock_for(Duration::from_millis(30)).is_none()
208 })
209 .join()
210 .unwrap();
211 assert!(timed_out);
212 drop(g);
213 }
214
215 #[test]
216 fn mutex_get_n_waiters() {
217 let m = Arc::new(Mutex::new(()));
218 let _g = m.lock();
219 let m2 = m.clone();
220 let barrier = Arc::new(std::sync::Barrier::new(2));
221 let b2 = barrier.clone();
222 let handle = std::thread::spawn(move || {
223 b2.wait();
224 let _g2 = m2.lock();
225 });
226 barrier.wait();
227 std::thread::sleep(Duration::from_millis(10));
228 assert!(unsafe { m.raw().get_n_waiters() } >= 1 || m.is_locked());
230 drop(_g);
231 handle.join().unwrap();
232 }
233
234 #[test]
235 fn mutex_force_unlock() {
236 let m = Mutex::new(());
237 let _g = m.lock();
238 unsafe { m.force_unlock() };
239 assert!(m.try_lock().is_some());
241 }
242
243 #[test]
246 fn rwlock_basic_read_write() {
247 let rw = RwLock::new(0i32);
248 *rw.write() = 99;
249 assert_eq!(*rw.read(), 99);
250 }
251
252 #[test]
253 fn rwlock_multiple_readers() {
254 let rw = Arc::new(RwLock::new(42i32));
255 let rw2 = rw.clone();
256 let g1 = rw.read();
257 let handle = std::thread::spawn(move || {
258 let g2 = rw2.read();
259 *g2
260 });
261 assert_eq!(*g1, 42);
262 assert_eq!(handle.join().unwrap(), 42);
263 }
264
265 #[test]
266 fn rwlock_exclusive_blocks_readers() {
267 let rw = Arc::new(RwLock::new(()));
268 let _wg = rw.write();
269 let rw2 = rw.clone();
270 let failed = std::thread::spawn(move || rw2.try_read().is_none())
271 .join()
272 .unwrap();
273 assert!(failed);
274 }
275
276 #[test]
277 fn rwlock_is_locked_exclusive() {
278 let rw = RwLock::new(());
279 assert!(!rw.is_locked_exclusive());
280 let _wg = rw.write();
281 assert!(rw.is_locked_exclusive());
282 }
283
284 #[test]
285 fn rwlock_try_write_for_timeout() {
286 let rw = Arc::new(RwLock::new(()));
287 let _wg = rw.write();
288 let rw2 = rw.clone();
289 let timed_out = std::thread::spawn(move || {
290 rw2.try_write_for(Duration::from_millis(30)).is_none()
291 })
292 .join()
293 .unwrap();
294 assert!(timed_out);
295 }
296
297 #[test]
298 fn rwlock_try_read_for_timeout() {
299 let rw = Arc::new(RwLock::new(()));
300 let _wg = rw.write();
301 let rw2 = rw.clone();
302 let timed_out = std::thread::spawn(move || {
303 rw2.try_read_for(Duration::from_millis(30)).is_none()
304 })
305 .join()
306 .unwrap();
307 assert!(timed_out);
308 }
309
310 #[test]
313 fn raw_mutex_const_init_and_lock_unlock() {
314 use lock_api::RawMutex as RawMutexTrait;
315 let raw = NoxuRawMutex::INIT;
316 assert!(!raw.is_locked());
317 raw.lock();
318 assert!(raw.is_locked());
319 unsafe { raw.unlock() };
320 assert!(!raw.is_locked());
321 }
322}