1 use crate::sync::batch_semaphore::Semaphore; 2 use std::marker::PhantomData; 3 use std::{fmt, mem, ops}; 4 5 /// RAII structure used to release the shared read access of a lock when 6 /// dropped. 7 /// 8 /// This structure is created by the [`read`] method on 9 /// [`RwLock`]. 10 /// 11 /// [`read`]: method@crate::sync::RwLock::read 12 /// [`RwLock`]: struct@crate::sync::RwLock 13 #[clippy::has_significant_drop] 14 #[must_use = "if unused the RwLock will immediately unlock"] 15 pub struct RwLockReadGuard<'a, T: ?Sized> { 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) s: &'a Semaphore, 21 pub(super) data: *const T, 22 pub(super) marker: PhantomData<&'a T>, 23 } 24 25 #[allow(dead_code)] // Unused fields are still used in Drop. 26 struct Inner<'a, T: ?Sized> { 27 #[cfg(all(tokio_unstable, feature = "tracing"))] 28 resource_span: tracing::Span, 29 s: &'a Semaphore, 30 data: *const T, 31 } 32 33 impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { skip_drop(self) -> Inner<'a, T>34 fn skip_drop(self) -> Inner<'a, T> { 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 Inner { 39 #[cfg(all(tokio_unstable, feature = "tracing"))] 40 resource_span: unsafe { std::ptr::read(&me.resource_span) }, 41 s: me.s, 42 data: me.data, 43 } 44 } 45 46 /// Makes a new `RwLockReadGuard` for a component of the locked data. 47 /// 48 /// This operation cannot fail as the `RwLockReadGuard` passed in already 49 /// locked the data. 50 /// 51 /// This is an associated function that needs to be 52 /// used as `RwLockReadGuard::map(...)`. A method would interfere with 53 /// methods of the same name on the contents of the locked data. 54 /// 55 /// This is an asynchronous version of [`RwLockReadGuard::map`] from the 56 /// [`parking_lot` crate]. 57 /// 58 /// [`RwLockReadGuard::map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.map 59 /// [`parking_lot` crate]: https://crates.io/crates/parking_lot 60 /// 61 /// # Examples 62 /// 63 /// ``` 64 /// use tokio::sync::{RwLock, RwLockReadGuard}; 65 /// 66 /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 67 /// struct Foo(u32); 68 /// 69 /// # #[tokio::main] 70 /// # async fn main() { 71 /// let lock = RwLock::new(Foo(1)); 72 /// 73 /// let guard = lock.read().await; 74 /// let guard = RwLockReadGuard::map(guard, |f| &f.0); 75 /// 76 /// assert_eq!(1, *guard); 77 /// # } 78 /// ``` 79 #[inline] map<F, U: ?Sized>(this: Self, f: F) -> RwLockReadGuard<'a, U> where F: FnOnce(&T) -> &U,80 pub fn map<F, U: ?Sized>(this: Self, f: F) -> RwLockReadGuard<'a, U> 81 where 82 F: FnOnce(&T) -> &U, 83 { 84 let data = f(&*this) as *const U; 85 let this = this.skip_drop(); 86 87 RwLockReadGuard { 88 s: this.s, 89 data, 90 marker: PhantomData, 91 #[cfg(all(tokio_unstable, feature = "tracing"))] 92 resource_span: this.resource_span, 93 } 94 } 95 96 /// Attempts to make a new [`RwLockReadGuard`] for a component of the 97 /// locked data. The original guard is returned if the closure returns 98 /// `None`. 99 /// 100 /// This operation cannot fail as the `RwLockReadGuard` passed in already 101 /// locked the data. 102 /// 103 /// This is an associated function that needs to be used as 104 /// `RwLockReadGuard::try_map(..)`. A method would interfere with methods of the 105 /// same name on the contents of the locked data. 106 /// 107 /// This is an asynchronous version of [`RwLockReadGuard::try_map`] from the 108 /// [`parking_lot` crate]. 109 /// 110 /// [`RwLockReadGuard::try_map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.try_map 111 /// [`parking_lot` crate]: https://crates.io/crates/parking_lot 112 /// 113 /// # Examples 114 /// 115 /// ``` 116 /// use tokio::sync::{RwLock, RwLockReadGuard}; 117 /// 118 /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 119 /// struct Foo(u32); 120 /// 121 /// # #[tokio::main] 122 /// # async fn main() { 123 /// let lock = RwLock::new(Foo(1)); 124 /// 125 /// let guard = lock.read().await; 126 /// let guard = RwLockReadGuard::try_map(guard, |f| Some(&f.0)).expect("should not fail"); 127 /// 128 /// assert_eq!(1, *guard); 129 /// # } 130 /// ``` 131 #[inline] try_map<F, U: ?Sized>(this: Self, f: F) -> Result<RwLockReadGuard<'a, U>, Self> where F: FnOnce(&T) -> Option<&U>,132 pub fn try_map<F, U: ?Sized>(this: Self, f: F) -> Result<RwLockReadGuard<'a, U>, Self> 133 where 134 F: FnOnce(&T) -> Option<&U>, 135 { 136 let data = match f(&*this) { 137 Some(data) => data as *const U, 138 None => return Err(this), 139 }; 140 let this = this.skip_drop(); 141 142 Ok(RwLockReadGuard { 143 s: this.s, 144 data, 145 marker: PhantomData, 146 #[cfg(all(tokio_unstable, feature = "tracing"))] 147 resource_span: this.resource_span, 148 }) 149 } 150 } 151 152 impl<T: ?Sized> ops::Deref for RwLockReadGuard<'_, T> { 153 type Target = T; 154 deref(&self) -> &T155 fn deref(&self) -> &T { 156 unsafe { &*self.data } 157 } 158 } 159 160 impl<'a, T: ?Sized> fmt::Debug for RwLockReadGuard<'a, T> 161 where 162 T: fmt::Debug, 163 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 165 fmt::Debug::fmt(&**self, f) 166 } 167 } 168 169 impl<'a, T: ?Sized> fmt::Display for RwLockReadGuard<'a, T> 170 where 171 T: fmt::Display, 172 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 174 fmt::Display::fmt(&**self, f) 175 } 176 } 177 178 impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { drop(&mut self)179 fn drop(&mut self) { 180 self.s.release(1); 181 182 #[cfg(all(tokio_unstable, feature = "tracing"))] 183 self.resource_span.in_scope(|| { 184 tracing::trace!( 185 target: "runtime::resource::state_update", 186 current_readers = 1, 187 current_readers.op = "sub", 188 ) 189 }); 190 } 191 } 192