1 use crate::sync::rwlock::RwLock; 2 use std::marker::PhantomData; 3 use std::sync::Arc; 4 use std::{fmt, mem, ops, ptr}; 5 6 /// Owned RAII structure used to release the shared read access of a lock when 7 /// dropped. 8 /// 9 /// This structure is created by the [`read_owned`] method on 10 /// [`RwLock`]. 11 /// 12 /// [`read_owned`]: method@crate::sync::RwLock::read_owned 13 /// [`RwLock`]: struct@crate::sync::RwLock 14 #[clippy::has_significant_drop] 15 pub struct OwnedRwLockReadGuard<T: ?Sized, U: ?Sized = T> { 16 // When changing the fields in this struct, make sure to update the 17 // `skip_drop` method. 18 #[cfg(all(tokio_unstable, feature = "tracing"))] 19 pub(super) resource_span: tracing::Span, 20 pub(super) lock: Arc<RwLock<T>>, 21 pub(super) data: *const U, 22 pub(super) _p: PhantomData<T>, 23 } 24 25 #[allow(dead_code)] // Unused fields are still used in Drop. 26 struct Inner<T: ?Sized, U: ?Sized> { 27 #[cfg(all(tokio_unstable, feature = "tracing"))] 28 resource_span: tracing::Span, 29 lock: Arc<RwLock<T>>, 30 data: *const U, 31 } 32 33 impl<T: ?Sized, U: ?Sized> OwnedRwLockReadGuard<T, U> { skip_drop(self) -> Inner<T, U>34 fn skip_drop(self) -> Inner<T, U> { 35 let me = mem::ManuallyDrop::new(self); 36 // SAFETY: This duplicates the values in every field of the guard, then 37 // forgets the originals, so in the end no value is duplicated. 38 unsafe { 39 Inner { 40 #[cfg(all(tokio_unstable, feature = "tracing"))] 41 resource_span: ptr::read(&me.resource_span), 42 lock: ptr::read(&me.lock), 43 data: me.data, 44 } 45 } 46 } 47 48 /// Makes a new `OwnedRwLockReadGuard` for a component of the locked data. 49 /// This operation cannot fail as the `OwnedRwLockReadGuard` passed in 50 /// already locked the data. 51 /// 52 /// This is an associated function that needs to be 53 /// used as `OwnedRwLockReadGuard::map(...)`. A method would interfere with 54 /// methods of the same name on the contents of the locked data. 55 /// 56 /// # Examples 57 /// 58 /// ``` 59 /// use std::sync::Arc; 60 /// use tokio::sync::{RwLock, OwnedRwLockReadGuard}; 61 /// 62 /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 63 /// struct Foo(u32); 64 /// 65 /// # #[tokio::main] 66 /// # async fn main() { 67 /// let lock = Arc::new(RwLock::new(Foo(1))); 68 /// 69 /// let guard = lock.read_owned().await; 70 /// let guard = OwnedRwLockReadGuard::map(guard, |f| &f.0); 71 /// 72 /// assert_eq!(1, *guard); 73 /// # } 74 /// ``` 75 #[inline] map<F, V: ?Sized>(this: Self, f: F) -> OwnedRwLockReadGuard<T, V> where F: FnOnce(&U) -> &V,76 pub fn map<F, V: ?Sized>(this: Self, f: F) -> OwnedRwLockReadGuard<T, V> 77 where 78 F: FnOnce(&U) -> &V, 79 { 80 let data = f(&*this) as *const V; 81 let this = this.skip_drop(); 82 83 OwnedRwLockReadGuard { 84 lock: this.lock, 85 data, 86 _p: PhantomData, 87 #[cfg(all(tokio_unstable, feature = "tracing"))] 88 resource_span: this.resource_span, 89 } 90 } 91 92 /// Attempts to make a new [`OwnedRwLockReadGuard`] for a component of the 93 /// locked data. The original guard is returned if the closure returns 94 /// `None`. 95 /// 96 /// This operation cannot fail as the `OwnedRwLockReadGuard` passed in 97 /// already locked the data. 98 /// 99 /// This is an associated function that needs to be used as 100 /// `OwnedRwLockReadGuard::try_map(..)`. A method would interfere with 101 /// methods of the same name on the contents of the locked data. 102 /// 103 /// # Examples 104 /// 105 /// ``` 106 /// use std::sync::Arc; 107 /// use tokio::sync::{RwLock, OwnedRwLockReadGuard}; 108 /// 109 /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 110 /// struct Foo(u32); 111 /// 112 /// # #[tokio::main] 113 /// # async fn main() { 114 /// let lock = Arc::new(RwLock::new(Foo(1))); 115 /// 116 /// let guard = lock.read_owned().await; 117 /// let guard = OwnedRwLockReadGuard::try_map(guard, |f| Some(&f.0)).expect("should not fail"); 118 /// 119 /// assert_eq!(1, *guard); 120 /// # } 121 /// ``` 122 #[inline] try_map<F, V: ?Sized>(this: Self, f: F) -> Result<OwnedRwLockReadGuard<T, V>, Self> where F: FnOnce(&U) -> Option<&V>,123 pub fn try_map<F, V: ?Sized>(this: Self, f: F) -> Result<OwnedRwLockReadGuard<T, V>, Self> 124 where 125 F: FnOnce(&U) -> Option<&V>, 126 { 127 let data = match f(&*this) { 128 Some(data) => data as *const V, 129 None => return Err(this), 130 }; 131 let this = this.skip_drop(); 132 133 Ok(OwnedRwLockReadGuard { 134 lock: this.lock, 135 data, 136 _p: PhantomData, 137 #[cfg(all(tokio_unstable, feature = "tracing"))] 138 resource_span: this.resource_span, 139 }) 140 } 141 142 /// Returns a reference to the original `Arc<RwLock>`. 143 /// 144 /// # Examples 145 /// 146 /// ``` 147 /// use std::sync::Arc; 148 /// use tokio::sync::{RwLock, OwnedRwLockReadGuard}; 149 /// 150 /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 151 /// struct Foo(u32); 152 /// 153 /// # #[tokio::main] 154 /// # async fn main() { 155 /// let lock = Arc::new(RwLock::new(Foo(1))); 156 /// 157 /// let guard = lock.clone().read_owned().await; 158 /// assert!(Arc::ptr_eq(&lock, OwnedRwLockReadGuard::rwlock(&guard))); 159 /// 160 /// let guard = OwnedRwLockReadGuard::map(guard, |f| &f.0); 161 /// assert!(Arc::ptr_eq(&lock, OwnedRwLockReadGuard::rwlock(&guard))); 162 /// # } 163 /// ``` rwlock(this: &Self) -> &Arc<RwLock<T>>164 pub fn rwlock(this: &Self) -> &Arc<RwLock<T>> { 165 &this.lock 166 } 167 } 168 169 impl<T: ?Sized, U: ?Sized> ops::Deref for OwnedRwLockReadGuard<T, U> { 170 type Target = U; 171 deref(&self) -> &U172 fn deref(&self) -> &U { 173 unsafe { &*self.data } 174 } 175 } 176 177 impl<T: ?Sized, U: ?Sized> fmt::Debug for OwnedRwLockReadGuard<T, U> 178 where 179 U: fmt::Debug, 180 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 182 fmt::Debug::fmt(&**self, f) 183 } 184 } 185 186 impl<T: ?Sized, U: ?Sized> fmt::Display for OwnedRwLockReadGuard<T, U> 187 where 188 U: fmt::Display, 189 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 191 fmt::Display::fmt(&**self, f) 192 } 193 } 194 195 impl<T: ?Sized, U: ?Sized> Drop for OwnedRwLockReadGuard<T, U> { drop(&mut self)196 fn drop(&mut self) { 197 self.lock.s.release(1); 198 199 #[cfg(all(tokio_unstable, feature = "tracing"))] 200 self.resource_span.in_scope(|| { 201 tracing::trace!( 202 target: "runtime::resource::state_update", 203 current_readers = 1, 204 current_readers.op = "sub", 205 ) 206 }); 207 } 208 } 209