memscope_rs/core/
simple_mutex.rs1#[cfg(feature = "parking-lot")]
8pub type OptimizedMutex<T> = parking_lot::Mutex<T>;
9
10#[cfg(not(feature = "parking-lot"))]
11pub type OptimizedMutex<T> = std::sync::Mutex<T>;
12
13pub struct SimpleMutex<T> {
15 inner: OptimizedMutex<T>,
16 #[cfg(debug_assertions)]
17 access_count: std::sync::atomic::AtomicU64,
18}
19
20impl<T> SimpleMutex<T> {
21 pub fn new(data: T) -> Self {
23 Self {
24 inner: OptimizedMutex::new(data),
25 #[cfg(debug_assertions)]
26 access_count: std::sync::atomic::AtomicU64::new(0),
27 }
28 }
29
30 #[cfg(feature = "parking-lot")]
32 pub fn lock(&self) -> parking_lot::MutexGuard<'_, T> {
33 #[cfg(debug_assertions)]
34 self.access_count
35 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
36
37 self.inner.lock()
38 }
39
40 #[cfg(not(feature = "parking-lot"))]
42 pub fn lock(
43 &self,
44 ) -> Result<std::sync::MutexGuard<T>, std::sync::PoisonError<std::sync::MutexGuard<T>>> {
45 #[cfg(debug_assertions)]
46 self.access_count
47 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
48
49 self.inner.lock()
50 }
51
52 #[cfg(feature = "parking-lot")]
54 pub fn try_lock(&self) -> Option<parking_lot::MutexGuard<'_, T>> {
55 #[cfg(debug_assertions)]
56 self.access_count
57 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
58
59 self.inner.try_lock()
60 }
61
62 #[cfg(not(feature = "parking-lot"))]
64 pub fn try_lock(
65 &self,
66 ) -> Result<std::sync::MutexGuard<T>, std::sync::TryLockError<std::sync::MutexGuard<T>>> {
67 #[cfg(debug_assertions)]
68 self.access_count
69 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
70
71 self.inner.try_lock()
72 }
73
74 #[cfg(debug_assertions)]
76 pub fn access_count(&self) -> u64 {
77 self.access_count.load(std::sync::atomic::Ordering::Relaxed)
78 }
79
80 #[cfg(not(debug_assertions))]
82 pub fn access_count(&self) -> u64 {
83 0
84 }
85}
86
87impl<T: Default> Default for SimpleMutex<T> {
88 fn default() -> Self {
89 Self::new(T::default())
90 }
91}
92
93impl<T> SimpleMutex<T> {
95 #[cfg(feature = "parking-lot")]
97 pub fn safe_lock(&self) -> crate::core::types::TrackingResult<parking_lot::MutexGuard<'_, T>> {
98 Ok(self.lock())
100 }
101
102 #[cfg(not(feature = "parking-lot"))]
103 pub fn safe_lock(&self) -> crate::core::types::TrackingResult<std::sync::MutexGuard<'_, T>> {
104 self.lock().map_err(|_| {
106 crate::core::types::TrackingError::LockError("Failed to acquire mutex lock".to_string())
107 })
108 }
109
110 #[cfg(feature = "parking-lot")]
112 pub fn try_safe_lock(
113 &self,
114 ) -> crate::core::types::TrackingResult<Option<parking_lot::MutexGuard<'_, T>>> {
115 Ok(self.try_lock())
117 }
118
119 #[cfg(not(feature = "parking-lot"))]
120 pub fn try_safe_lock(
121 &self,
122 ) -> crate::core::types::TrackingResult<Option<std::sync::MutexGuard<'_, T>>> {
123 match self.try_lock() {
125 Ok(guard) => Ok(Some(guard)),
126 Err(std::sync::TryLockError::WouldBlock) => Ok(None),
127 Err(_) => Err(crate::core::types::TrackingError::LockError(
128 "Failed to try acquire mutex lock".to_string(),
129 )),
130 }
131 }
132}
133
134unsafe impl<T: Send> Send for SimpleMutex<T> {}
136
137unsafe impl<T: Send> Sync for SimpleMutex<T> {}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use std::sync::Arc;
144 use std::thread;
145
146 #[test]
147 fn test_simple_mutex_creation() {
148 let mutex = SimpleMutex::new(42);
149 assert_eq!(mutex.access_count(), 0);
150 }
151
152 #[test]
153 fn test_simple_mutex_lock() {
154 let mutex = SimpleMutex::new(42);
155
156 #[cfg(feature = "parking-lot")]
157 {
158 let guard = mutex.lock();
159 assert_eq!(*guard, 42);
160 }
161
162 #[cfg(not(feature = "parking-lot"))]
163 {
164 let guard = mutex.lock().unwrap();
165 assert_eq!(*guard, 42);
166 }
167
168 #[cfg(debug_assertions)]
169 assert_eq!(mutex.access_count(), 1);
170 }
171
172 #[test]
173 fn test_simple_mutex_try_lock() {
174 let mutex = SimpleMutex::new(42);
175
176 #[cfg(feature = "parking-lot")]
177 {
178 let guard = mutex.try_lock();
179 assert!(guard.is_some());
180 assert_eq!(*guard.unwrap(), 42);
181 }
182
183 #[cfg(not(feature = "parking-lot"))]
184 {
185 let guard = mutex.try_lock();
186 assert!(guard.is_ok());
187 assert_eq!(*guard.unwrap(), 42);
188 }
189
190 #[cfg(debug_assertions)]
191 assert_eq!(mutex.access_count(), 1);
192 }
193
194 #[test]
195 fn test_simple_mutex_concurrent_access() {
196 let mutex = Arc::new(SimpleMutex::new(0));
197 let mut handles = vec![];
198
199 for _ in 0..10 {
200 let mutex_clone = Arc::clone(&mutex);
201 let handle = thread::spawn(move || {
202 #[cfg(feature = "parking-lot")]
203 {
204 let mut guard = mutex_clone.lock();
205 *guard += 1;
206 }
207
208 #[cfg(not(feature = "parking-lot"))]
209 {
210 let mut guard = mutex_clone
211 .lock()
212 .expect("Mutex should not be poisoned in thread");
213 *guard += 1;
214 }
215 });
216 handles.push(handle);
217 }
218
219 for handle in handles {
220 handle.join().expect("Thread should complete successfully");
221 }
222
223 #[cfg(feature = "parking-lot")]
224 {
225 let guard = mutex.lock();
226 assert_eq!(*guard, 10);
227 }
228
229 #[cfg(not(feature = "parking-lot"))]
230 {
231 let guard = mutex.lock().unwrap();
232 assert_eq!(*guard, 10);
233 }
234 }
235
236 #[test]
237 fn test_simple_mutex_default() {
238 let mutex: SimpleMutex<i32> = SimpleMutex::default();
239
240 #[cfg(feature = "parking-lot")]
241 {
242 let guard = mutex.lock();
243 assert_eq!(*guard, 0);
244 }
245
246 #[cfg(not(feature = "parking-lot"))]
247 {
248 let guard = mutex.lock().unwrap();
249 assert_eq!(*guard, 0);
250 }
251 }
252
253 #[test]
254 #[cfg(debug_assertions)]
255 fn test_access_count_tracking() {
256 let mutex = SimpleMutex::new(42);
257 assert_eq!(mutex.access_count(), 0);
258
259 #[cfg(feature = "parking-lot")]
260 {
261 let _guard1 = mutex.lock();
262 assert_eq!(mutex.access_count(), 1);
263
264 let _guard2 = mutex.try_lock();
265 assert_eq!(mutex.access_count(), 2);
266 }
267
268 #[cfg(not(feature = "parking-lot"))]
269 {
270 let _guard1 = mutex.lock().unwrap();
271 assert_eq!(mutex.access_count(), 1);
272
273 let _guard2 = mutex.try_lock().unwrap();
274 assert_eq!(mutex.access_count(), 2);
275 }
276 }
277
278 #[test]
279 #[cfg(not(debug_assertions))]
280 fn test_access_count_release_mode() {
281 let mutex = SimpleMutex::new(42);
282
283 #[cfg(feature = "parking-lot")]
284 {
285 let _guard = mutex.lock();
286 }
287
288 #[cfg(not(feature = "parking-lot"))]
289 {
290 let _guard = mutex.lock().unwrap();
291 }
292
293 assert_eq!(mutex.access_count(), 0);
295 }
296}