• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::sync::rwlock::owned_read_guard::OwnedRwLockReadGuard;
2 use crate::sync::rwlock::owned_write_guard_mapped::OwnedRwLockMappedWriteGuard;
3 use crate::sync::rwlock::RwLock;
4 use std::fmt;
5 use std::marker::PhantomData;
6 use std::mem::{self, ManuallyDrop};
7 use std::ops;
8 use std::sync::Arc;
9 
10 /// Owned RAII structure used to release the exclusive write access of a lock when
11 /// dropped.
12 ///
13 /// This structure is created by the [`write_owned`] method
14 /// on [`RwLock`].
15 ///
16 /// [`write_owned`]: method@crate::sync::RwLock::write_owned
17 /// [`RwLock`]: struct@crate::sync::RwLock
18 pub struct OwnedRwLockWriteGuard<T: ?Sized> {
19     pub(super) permits_acquired: u32,
20     // ManuallyDrop allows us to destructure into this field without running the destructor.
21     pub(super) lock: ManuallyDrop<Arc<RwLock<T>>>,
22     pub(super) data: *mut T,
23     pub(super) _p: PhantomData<T>,
24 }
25 
26 impl<T: ?Sized> OwnedRwLockWriteGuard<T> {
27     /// Make a new [`OwnedRwLockMappedWriteGuard`] for a component of the locked
28     /// data.
29     ///
30     /// This operation cannot fail as the `OwnedRwLockWriteGuard` passed in
31     /// already locked the data.
32     ///
33     /// This is an associated function that needs to be used as
34     /// `OwnedRwLockWriteGuard::map(..)`. A method would interfere with methods
35     /// of the same name on the contents of the locked data.
36     ///
37     /// # Examples
38     ///
39     /// ```
40     /// use std::sync::Arc;
41     /// use tokio::sync::{RwLock, OwnedRwLockWriteGuard};
42     ///
43     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
44     /// struct Foo(u32);
45     ///
46     /// # #[tokio::main]
47     /// # async fn main() {
48     /// let lock = Arc::new(RwLock::new(Foo(1)));
49     ///
50     /// {
51     ///     let lock = Arc::clone(&lock);
52     ///     let mut mapped = OwnedRwLockWriteGuard::map(lock.write_owned().await, |f| &mut f.0);
53     ///     *mapped = 2;
54     /// }
55     ///
56     /// assert_eq!(Foo(2), *lock.read().await);
57     /// # }
58     /// ```
59     #[inline]
map<F, U: ?Sized>(mut this: Self, f: F) -> OwnedRwLockMappedWriteGuard<T, U> where F: FnOnce(&mut T) -> &mut U,60     pub fn map<F, U: ?Sized>(mut this: Self, f: F) -> OwnedRwLockMappedWriteGuard<T, U>
61     where
62         F: FnOnce(&mut T) -> &mut U,
63     {
64         let data = f(&mut *this) as *mut U;
65         let lock = unsafe { ManuallyDrop::take(&mut this.lock) };
66         let permits_acquired = this.permits_acquired;
67         // NB: Forget to avoid drop impl from being called.
68         mem::forget(this);
69         OwnedRwLockMappedWriteGuard {
70             permits_acquired,
71             lock: ManuallyDrop::new(lock),
72             data,
73             _p: PhantomData,
74         }
75     }
76 
77     /// Attempts to make  a new [`OwnedRwLockMappedWriteGuard`] for a component
78     /// of the locked data. The original guard is returned if the closure
79     /// returns `None`.
80     ///
81     /// This operation cannot fail as the `OwnedRwLockWriteGuard` passed in
82     /// already locked the data.
83     ///
84     /// This is an associated function that needs to be
85     /// used as `OwnedRwLockWriteGuard::try_map(...)`. A method would interfere
86     /// with methods of the same name on the contents of the locked data.
87     ///
88     /// [`RwLockMappedWriteGuard`]: struct@crate::sync::RwLockMappedWriteGuard
89     ///
90     /// # Examples
91     ///
92     /// ```
93     /// use std::sync::Arc;
94     /// use tokio::sync::{RwLock, OwnedRwLockWriteGuard};
95     ///
96     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
97     /// struct Foo(u32);
98     ///
99     /// # #[tokio::main]
100     /// # async fn main() {
101     /// let lock = Arc::new(RwLock::new(Foo(1)));
102     ///
103     /// {
104     ///     let guard = Arc::clone(&lock).write_owned().await;
105     ///     let mut guard = OwnedRwLockWriteGuard::try_map(guard, |f| Some(&mut f.0)).expect("should not fail");
106     ///     *guard = 2;
107     /// }
108     ///
109     /// assert_eq!(Foo(2), *lock.read().await);
110     /// # }
111     /// ```
112     #[inline]
try_map<F, U: ?Sized>( mut this: Self, f: F, ) -> Result<OwnedRwLockMappedWriteGuard<T, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>,113     pub fn try_map<F, U: ?Sized>(
114         mut this: Self,
115         f: F,
116     ) -> Result<OwnedRwLockMappedWriteGuard<T, U>, Self>
117     where
118         F: FnOnce(&mut T) -> Option<&mut U>,
119     {
120         let data = match f(&mut *this) {
121             Some(data) => data as *mut U,
122             None => return Err(this),
123         };
124         let permits_acquired = this.permits_acquired;
125         let lock = unsafe { ManuallyDrop::take(&mut this.lock) };
126         // NB: Forget to avoid drop impl from being called.
127         mem::forget(this);
128         Ok(OwnedRwLockMappedWriteGuard {
129             permits_acquired,
130             lock: ManuallyDrop::new(lock),
131             data,
132             _p: PhantomData,
133         })
134     }
135 
136     /// Converts this `OwnedRwLockWriteGuard` into an
137     /// `OwnedRwLockMappedWriteGuard`. This method can be used to store a
138     /// non-mapped guard in a struct field that expects a mapped guard.
139     ///
140     /// This is equivalent to calling `OwnedRwLockWriteGuard::map(guard, |me| me)`.
141     #[inline]
into_mapped(this: Self) -> OwnedRwLockMappedWriteGuard<T>142     pub fn into_mapped(this: Self) -> OwnedRwLockMappedWriteGuard<T> {
143         Self::map(this, |me| me)
144     }
145 
146     /// Atomically downgrades a write lock into a read lock without allowing
147     /// any writers to take exclusive access of the lock in the meantime.
148     ///
149     /// **Note:** This won't *necessarily* allow any additional readers to acquire
150     /// locks, since [`RwLock`] is fair and it is possible that a writer is next
151     /// in line.
152     ///
153     /// Returns an RAII guard which will drop this read access of the `RwLock`
154     /// when dropped.
155     ///
156     /// # Examples
157     ///
158     /// ```
159     /// # use tokio::sync::RwLock;
160     /// # use std::sync::Arc;
161     /// #
162     /// # #[tokio::main]
163     /// # async fn main() {
164     /// let lock = Arc::new(RwLock::new(1));
165     ///
166     /// let n = lock.clone().write_owned().await;
167     ///
168     /// let cloned_lock = lock.clone();
169     /// let handle = tokio::spawn(async move {
170     ///     *cloned_lock.write_owned().await = 2;
171     /// });
172     ///
173     /// let n = n.downgrade();
174     /// assert_eq!(*n, 1, "downgrade is atomic");
175     ///
176     /// drop(n);
177     /// handle.await.unwrap();
178     /// assert_eq!(*lock.read().await, 2, "second writer obtained write lock");
179     /// # }
180     /// ```
downgrade(mut self) -> OwnedRwLockReadGuard<T>181     pub fn downgrade(mut self) -> OwnedRwLockReadGuard<T> {
182         let lock = unsafe { ManuallyDrop::take(&mut self.lock) };
183         let data = self.data;
184 
185         // Release all but one of the permits held by the write guard
186         lock.s.release((self.permits_acquired - 1) as usize);
187         // NB: Forget to avoid drop impl from being called.
188         mem::forget(self);
189         OwnedRwLockReadGuard {
190             lock: ManuallyDrop::new(lock),
191             data,
192             _p: PhantomData,
193         }
194     }
195 }
196 
197 impl<T: ?Sized> ops::Deref for OwnedRwLockWriteGuard<T> {
198     type Target = T;
199 
deref(&self) -> &T200     fn deref(&self) -> &T {
201         unsafe { &*self.data }
202     }
203 }
204 
205 impl<T: ?Sized> ops::DerefMut for OwnedRwLockWriteGuard<T> {
deref_mut(&mut self) -> &mut T206     fn deref_mut(&mut self) -> &mut T {
207         unsafe { &mut *self.data }
208     }
209 }
210 
211 impl<T: ?Sized> fmt::Debug for OwnedRwLockWriteGuard<T>
212 where
213     T: fmt::Debug,
214 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result215     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216         fmt::Debug::fmt(&**self, f)
217     }
218 }
219 
220 impl<T: ?Sized> fmt::Display for OwnedRwLockWriteGuard<T>
221 where
222     T: fmt::Display,
223 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result224     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225         fmt::Display::fmt(&**self, f)
226     }
227 }
228 
229 impl<T: ?Sized> Drop for OwnedRwLockWriteGuard<T> {
drop(&mut self)230     fn drop(&mut self) {
231         self.lock.s.release(self.permits_acquired as usize);
232         unsafe { ManuallyDrop::drop(&mut self.lock) };
233     }
234 }
235