mutex_timeouts/
std.rs

1use std::sync::{Arc, Mutex, MutexGuard};
2use std::sync::atomic::AtomicU64;
3use std::time::Duration;
4use once_cell::sync::Lazy;
5
6pub static GLOBAL_STD_TIMEOUT: Lazy<Arc<AtomicU64>> = Lazy::new(|| Arc::new(AtomicU64::new(5)));
7
8/// A wrapper around `std::sync::Mutex` that allows for a timeout to be set.
9pub struct MutexWithTimeout<T> {
10    inner: Mutex<T>,
11    timeout: Duration,
12}
13
14impl<T> MutexWithTimeout<T> {
15    /// Creates a new `MutexWithTimeout` with the default timeout.
16    pub fn new(inner: T) -> Self {
17        Self {
18            inner: Mutex::new(inner),
19            timeout: Duration::from_secs(GLOBAL_STD_TIMEOUT.load(std::sync::atomic::Ordering::Relaxed)),
20        }
21    }
22
23    /// Creates a new `MutexWithTimeout` with the given timeout.
24    pub fn new_with_timeout(inner: T, timeout: Duration) -> Self {
25        Self {
26            inner: Mutex::new(inner),
27            timeout,
28        }
29    }
30
31
32    /// Will attempt to lock the inner `std::sync::Mutex`.
33    /// If the lock is not acquired within the timeout, `None` will be returned.
34    pub fn lock(&self) -> Option<MutexGuard<T>> {
35        let start = std::time::Instant::now();
36        loop {
37            if let Ok(guard) = self.inner.try_lock() {
38                return Some(guard);
39            }
40
41            if start.elapsed() > self.timeout {
42                break;
43            }
44        }
45        None
46    }
47
48    /// Calls the inner mutex's `try_lock` method.
49    pub fn try_lock(&self) -> Option<std::sync::MutexGuard<T>> {
50        self.inner.try_lock().ok()
51    }
52}