memscope_rs/core/
safe_operations.rs1use crate::core::types::TrackingResult;
7use std::sync::{Mutex, RwLock};
8
9pub trait SafeLock<T> {
11 fn safe_lock(&self) -> TrackingResult<std::sync::MutexGuard<'_, T>>;
13
14 fn try_safe_lock(&self) -> TrackingResult<Option<std::sync::MutexGuard<'_, T>>>;
16}
17
18impl<T> SafeLock<T> for Mutex<T> {
19 fn safe_lock(&self) -> TrackingResult<std::sync::MutexGuard<'_, T>> {
20 self.lock().map_err(|e| {
21 crate::core::types::TrackingError::LockError(format!(
22 "Failed to acquire mutex lock: {e}",
23 ))
24 })
25 }
26
27 fn try_safe_lock(&self) -> TrackingResult<Option<std::sync::MutexGuard<'_, T>>> {
28 match self.try_lock() {
29 Ok(guard) => Ok(Some(guard)),
30 Err(std::sync::TryLockError::WouldBlock) => Ok(None),
31 Err(std::sync::TryLockError::Poisoned(e)) => Err(
32 crate::core::types::TrackingError::LockError(format!("Mutex poisoned: {e}")),
33 ),
34 }
35 }
36}
37
38pub trait SafeRwLock<T> {
40 fn safe_read(&self) -> TrackingResult<std::sync::RwLockReadGuard<'_, T>>;
42
43 fn safe_write(&self) -> TrackingResult<std::sync::RwLockWriteGuard<'_, T>>;
45}
46
47impl<T> SafeRwLock<T> for RwLock<T> {
48 fn safe_read(&self) -> TrackingResult<std::sync::RwLockReadGuard<'_, T>> {
49 self.read().map_err(|e| {
50 crate::core::types::TrackingError::LockError(format!(
51 "Failed to acquire read lock: {e}",
52 ))
53 })
54 }
55
56 fn safe_write(&self) -> TrackingResult<std::sync::RwLockWriteGuard<'_, T>> {
57 self.write().map_err(|e| {
58 crate::core::types::TrackingError::LockError(format!(
59 "Failed to acquire write lock: {e}",
60 ))
61 })
62 }
63}
64
65#[macro_export]
67macro_rules! safe_lock {
68 ($mutex:expr) => {
69 $mutex.safe_lock()?
70 };
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use std::sync::{Arc, Mutex, RwLock};
77 use std::thread;
78 use std::time::Duration;
79
80 #[test]
81 fn test_safe_mutex_lock() {
82 let mutex = Mutex::new(42);
83
84 let guard = mutex.safe_lock().unwrap();
85 assert_eq!(*guard, 42);
86 }
87
88 #[test]
89 fn test_safe_mutex_try_lock() {
90 let mutex = Mutex::new(42);
91
92 let guard = mutex.try_safe_lock().unwrap();
93 assert!(guard.is_some());
94 assert_eq!(*guard.unwrap(), 42);
95 }
96
97 #[test]
98 fn test_safe_mutex_try_lock_would_block() {
99 let mutex = Arc::new(Mutex::new(42));
100 let mutex_clone = Arc::clone(&mutex);
101
102 let _guard = mutex.safe_lock().unwrap();
103
104 let handle = thread::spawn(move || {
106 let result = mutex_clone.try_safe_lock().unwrap();
107 result.is_none()
108 });
109
110 assert!(handle.join().unwrap());
111 }
112
113 #[test]
114 fn test_safe_rwlock_read() {
115 let rwlock = RwLock::new(42);
116
117 let guard = rwlock.safe_read().unwrap();
118 assert_eq!(*guard, 42);
119 }
120
121 #[test]
122 fn test_safe_rwlock_write() {
123 let rwlock = RwLock::new(42);
124
125 let mut guard = rwlock.safe_write().unwrap();
126 *guard = 100;
127 drop(guard);
128
129 let guard = rwlock.safe_read().unwrap();
130 assert_eq!(*guard, 100);
131 }
132
133 #[test]
134 fn test_safe_rwlock_multiple_readers() {
135 let rwlock = Arc::new(RwLock::new(42));
136 let mut handles = vec![];
137
138 for _ in 0..5 {
140 let rwlock_clone = Arc::clone(&rwlock);
141 let handle = thread::spawn(move || {
142 let guard = rwlock_clone.safe_read().unwrap();
143 assert_eq!(*guard, 42);
144 thread::sleep(Duration::from_millis(10));
145 });
146 handles.push(handle);
147 }
148
149 for handle in handles {
150 handle.join().unwrap();
151 }
152 }
153
154 #[test]
155 fn test_safe_rwlock_writer_exclusivity() {
156 let rwlock = Arc::new(RwLock::new(0));
157 let rwlock_clone = Arc::clone(&rwlock);
158
159 let handle = thread::spawn(move || {
160 let mut guard = rwlock_clone.safe_write().unwrap();
161 *guard = 42;
162 thread::sleep(Duration::from_millis(50));
163 *guard = 100;
164 });
165
166 thread::sleep(Duration::from_millis(10));
168
169 let guard = rwlock.safe_read().unwrap();
171 assert_eq!(*guard, 100);
172
173 handle.join().unwrap();
174 }
175
176 #[test]
177 fn test_concurrent_safe_operations() {
178 let mutex = Arc::new(Mutex::new(0));
179 let mut handles = vec![];
180
181 for _ in 0..10 {
183 let mutex_clone = Arc::clone(&mutex);
184 let handle = thread::spawn(move || {
185 let mut guard = mutex_clone.safe_lock().unwrap();
186 *guard += 1;
187 });
188 handles.push(handle);
189 }
190
191 for handle in handles {
192 handle.join().unwrap();
193 }
194
195 let guard = mutex.safe_lock().unwrap();
196 assert_eq!(*guard, 10);
197 }
198
199 #[test]
200 fn test_safe_lock_macro() {
201 use crate::safe_lock;
202
203 let mutex = Mutex::new(42);
204
205 let result: Result<(), crate::core::types::TrackingError> = (|| {
207 let guard = safe_lock!(mutex);
208 assert_eq!(*guard, 42);
209 Ok(())
210 })();
211
212 assert!(result.is_ok());
213 }
214
215 #[test]
216 fn test_error_handling() {
217 let mutex = Mutex::new(42);
218
219 let result = mutex.safe_lock();
221 assert!(result.is_ok());
222
223 let try_result = mutex.try_safe_lock();
224 assert!(try_result.is_ok());
225 }
226}