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}