wasmer_wasix/utils/
owned_mutex_guard.rs

1/// Extends the standard library RwLock to include an owned version of the read
2/// and write locking functions.
3///
4/// This implementation contains unsafe code and has two levels of protection
5/// that prevent the lock from being released after the memory is freed.
6///
7/// 1. The internals use a Option which is cleared before the Drop completes
8/// 2. The Arc reference is placed as the last field which should be dropped last
9///    (https://doc.rust-lang.org/reference/destructors.html#:~:text=The%20fields%20of%20a%20struct,first%20element%20to%20the%20last.)
10use std::ops::{Deref, DerefMut};
11use std::sync::{Arc, LockResult, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
12
13/// Locks this rwlock with shared read access, blocking the current thread
14/// until it can be acquired.
15///
16/// The calling thread will be blocked until there are no more writers which
17/// hold the lock. There may be other readers currently inside the lock when
18/// this method returns. This method does not provide any guarantees with
19/// respect to the ordering of whether contentious readers or writers will
20/// acquire the lock first.
21///
22/// Returns an RAII guard which will release this thread's shared access
23/// once it is dropped.
24///
25/// # Errors
26///
27/// This function will return an error if the RwLock is poisoned. An RwLock
28/// is poisoned whenever a writer panics while holding an exclusive lock.
29/// The failure will occur immediately after the lock has been acquired.
30///
31/// # Panics
32///
33/// This function might panic when called if the lock is already held by the current thread.
34///
35// # Examples
36//
37// ```
38// use std::sync::{Arc, RwLock};
39// use std::thread;
40// use crate::utils::owned_mutex_guard::read_owned;
41//
42// let lock = Arc::new(RwLock::new(1));
43// let c_lock = Arc::clone(&lock);
44//
45// let n = read_owned(&lock).unwrap();
46// assert_eq!(*n, 1);
47//
48// thread::spawn(move || {
49//     let r = read_owned(&c_lock);
50//     assert!(r.is_ok());
51// }).join().unwrap();
52// ```
53pub(crate) fn read_owned<T>(lock: &Arc<RwLock<T>>) -> LockResult<OwnedRwLockReadGuard<T>> {
54    OwnedRwLockReadGuard::new(lock)
55}
56
57/// Locks this rwlock with exclusive write access, blocking the current
58/// thread until it can be acquired.
59///
60/// This function will not return while other writers or other readers
61/// currently have access to the lock.
62///
63/// Returns an RAII guard which will drop the write access of this rwlock
64/// when dropped.
65///
66/// # Errors
67///
68/// This function will return an error if the RwLock is poisoned. An RwLock
69/// is poisoned whenever a writer panics while holding an exclusive lock.
70/// An error will be returned when the lock is acquired.
71///
72/// # Panics
73///
74/// This function might panic when called if the lock is already held by the current thread.
75///
76// # Examples
77//
78// ```
79// use std::sync::RwLock;
80// use crate::utils::owned_mutex_guard::write_owned;
81//
82// let lock = RwLock::new(1);
83//
84// let mut n = write_owned(&lock).unwrap();
85// *n = 2;
86// ```
87pub(crate) fn write_owned<T>(lock: &Arc<RwLock<T>>) -> LockResult<OwnedRwLockWriteGuard<T>> {
88    OwnedRwLockWriteGuard::new(lock)
89}
90
91pub(crate) struct OwnedRwLockReadGuard<T: 'static> {
92    // This option is guaranteed to be `.is_some()` while in scope and cleared during the `Drop`
93    guard: Option<RwLockReadGuard<'static, T>>,
94    // as a precaution we keep the reference as the last field so that it is destructed after the guard
95    // (https://doc.rust-lang.org/reference/destructors.html#:~:text=The%20fields%20of%20a%20struct,first%20element%20to%20the%20last.)
96    #[allow(unused)]
97    ownership: Arc<RwLock<T>>,
98}
99
100unsafe impl<T> Send for OwnedRwLockReadGuard<T> where T: Send {}
101
102impl<T> Drop for OwnedRwLockReadGuard<T>
103where
104    T: Sized,
105{
106    fn drop(&mut self) {
107        // we must close the lock before we release the arc reference
108        self.guard.take();
109    }
110}
111
112impl<T> std::fmt::Debug for OwnedRwLockReadGuard<T>
113where
114    T: std::fmt::Debug,
115{
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        if let Some(guard) = self.guard.as_ref() {
118            write!(f, "{guard:?}")
119        } else {
120            write!(f, "none")
121        }
122    }
123}
124
125impl<T> std::fmt::Display for OwnedRwLockReadGuard<T>
126where
127    T: std::fmt::Display,
128{
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        if let Some(guard) = self.guard.as_ref() {
131            write!(f, "{guard}")
132        } else {
133            write!(f, "none")
134        }
135    }
136}
137
138impl<T> OwnedRwLockReadGuard<T> {
139    fn new(lock: &Arc<RwLock<T>>) -> LockResult<Self> {
140        let conv = |guard: RwLockReadGuard<'_, T>| {
141            let guard: RwLockReadGuard<'static, T> = unsafe { std::mem::transmute(guard) };
142            Self {
143                ownership: lock.clone(),
144                guard: Some(guard),
145            }
146        };
147        let guard = lock.read().map_err(|err| {
148            let guard = err.into_inner();
149            PoisonError::new(conv(guard))
150        })?;
151        Ok(conv(guard))
152    }
153
154    /// Converts this guard into an owned reference of the underlying lockable object
155    #[allow(dead_code)]
156    pub fn into_inner(self) -> Arc<RwLock<T>> {
157        self.ownership.clone()
158    }
159}
160
161impl<T> Deref for OwnedRwLockReadGuard<T> {
162    type Target = T;
163
164    fn deref(&self) -> &Self::Target {
165        self.guard.as_ref().unwrap()
166    }
167}
168
169pub(crate) struct OwnedRwLockWriteGuard<T: 'static> {
170    // This option is guaranteed to be `.is_some()` while in scope and cleared during the `Drop`
171    guard: Option<RwLockWriteGuard<'static, T>>,
172    // as a precaution we keep the reference as the last field so that it is destructed after the guard
173    // (https://doc.rust-lang.org/reference/destructors.html#:~:text=The%20fields%20of%20a%20struct,first%20element%20to%20the%20last.)
174    #[allow(unused)]
175    ownership: Arc<RwLock<T>>,
176}
177
178unsafe impl<T> Send for OwnedRwLockWriteGuard<T> where T: Send {}
179
180impl<T> Drop for OwnedRwLockWriteGuard<T>
181where
182    T: Sized,
183{
184    fn drop(&mut self) {
185        // we must close the lock before we release the arc reference
186        self.guard.take();
187    }
188}
189
190impl<T> std::fmt::Debug for OwnedRwLockWriteGuard<T>
191where
192    T: std::fmt::Debug,
193{
194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195        if let Some(guard) = self.guard.as_ref() {
196            write!(f, "{guard:?}")
197        } else {
198            write!(f, "none")
199        }
200    }
201}
202
203impl<T> std::fmt::Display for OwnedRwLockWriteGuard<T>
204where
205    T: std::fmt::Display,
206{
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        if let Some(guard) = self.guard.as_ref() {
209            write!(f, "{guard}")
210        } else {
211            write!(f, "none")
212        }
213    }
214}
215
216impl<T> OwnedRwLockWriteGuard<T> {
217    fn new(lock: &Arc<RwLock<T>>) -> LockResult<Self> {
218        let conv = |guard: RwLockWriteGuard<'_, T>| {
219            let guard: RwLockWriteGuard<'static, T> = unsafe { std::mem::transmute(guard) };
220            Self {
221                ownership: lock.clone(),
222                guard: Some(guard),
223            }
224        };
225        let guard = lock.write().map_err(|err| {
226            let guard = err.into_inner();
227            PoisonError::new(conv(guard))
228        })?;
229        Ok(conv(guard))
230    }
231
232    /// Converts this guard into an owned reference of the underlying lockable object
233    #[allow(dead_code)]
234    pub fn into_inner(self) -> Arc<RwLock<T>> {
235        self.ownership.clone()
236    }
237}
238
239impl<T> Deref for OwnedRwLockWriteGuard<T> {
240    type Target = T;
241
242    fn deref(&self) -> &Self::Target {
243        self.guard.as_ref().unwrap()
244    }
245}
246
247impl<T> DerefMut for OwnedRwLockWriteGuard<T> {
248    fn deref_mut(&mut self) -> &mut Self::Target {
249        self.guard.as_mut().unwrap()
250    }
251}