]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | #[cfg(all(test, not(target_os = "emscripten")))] |
2 | mod tests; | |
3 | ||
532ac7d7 XL |
4 | use crate::cell::UnsafeCell; |
5 | use crate::fmt; | |
532ac7d7 | 6 | use crate::ops::{Deref, DerefMut}; |
064997fb | 7 | use crate::ptr::NonNull; |
cdc7bbd5 | 8 | use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; |
532ac7d7 | 9 | use crate::sys_common::rwlock as sys; |
1a4d82fc JJ |
10 | |
11 | /// A reader-writer lock | |
12 | /// | |
13 | /// This type of lock allows a number of readers or at most one writer at any | |
14 | /// point in time. The write portion of this lock typically allows modification | |
15 | /// of the underlying data (exclusive access) and the read portion of this lock | |
16 | /// typically allows for read-only access (shared access). | |
17 | /// | |
ea8adc8c | 18 | /// In comparison, a [`Mutex`] does not distinguish between readers or writers |
0531ce1d XL |
19 | /// that acquire the lock, therefore blocking any threads waiting for the lock to |
20 | /// become available. An `RwLock` will allow any number of readers to acquire the | |
ea8adc8c XL |
21 | /// lock as long as a writer is not holding the lock. |
22 | /// | |
62682a34 SL |
23 | /// The priority policy of the lock is dependent on the underlying operating |
24 | /// system's implementation, and this type does not guarantee that any | |
6a06907d XL |
25 | /// particular policy will be used. In particular, a writer which is waiting to |
26 | /// acquire the lock in `write` might or might not block concurrent calls to | |
136023e0 XL |
27 | /// `read`, e.g.: |
28 | /// | |
29 | /// <details><summary>Potential deadlock example</summary> | |
30 | /// | |
31 | /// ```text | |
32 | /// // Thread 1 | // Thread 2 | |
33 | /// let _rg = lock.read(); | | |
34 | /// | // will block | |
35 | /// | let _wg = lock.write(); | |
36 | /// // may deadlock | | |
37 | /// let _rg = lock.read(); | | |
38 | /// ``` | |
39 | /// </details> | |
62682a34 | 40 | /// |
1a4d82fc | 41 | /// The type parameter `T` represents the data that this lock protects. It is |
ea8adc8c XL |
42 | /// required that `T` satisfies [`Send`] to be shared across threads and |
43 | /// [`Sync`] to allow concurrent access through readers. The RAII guards | |
dfeec247 | 44 | /// returned from the locking methods implement [`Deref`] (and [`DerefMut`] |
2c00a5a8 | 45 | /// for the `write` methods) to allow access to the content of the lock. |
1a4d82fc JJ |
46 | /// |
47 | /// # Poisoning | |
48 | /// | |
ea8adc8c | 49 | /// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however, |
a7813a04 | 50 | /// that an `RwLock` may only be poisoned if a panic occurs while it is locked |
1a4d82fc JJ |
51 | /// exclusively (write mode). If a panic occurs in any reader, then the lock |
52 | /// will not be poisoned. | |
53 | /// | |
54 | /// # Examples | |
55 | /// | |
56 | /// ``` | |
57 | /// use std::sync::RwLock; | |
58 | /// | |
85aaf69f | 59 | /// let lock = RwLock::new(5); |
1a4d82fc JJ |
60 | /// |
61 | /// // many reader locks can be held at once | |
62 | /// { | |
63 | /// let r1 = lock.read().unwrap(); | |
64 | /// let r2 = lock.read().unwrap(); | |
65 | /// assert_eq!(*r1, 5); | |
66 | /// assert_eq!(*r2, 5); | |
67 | /// } // read locks are dropped at this point | |
68 | /// | |
69 | /// // only one write lock may be held, however | |
70 | /// { | |
71 | /// let mut w = lock.write().unwrap(); | |
72 | /// *w += 1; | |
73 | /// assert_eq!(*w, 6); | |
74 | /// } // write lock is dropped here | |
75 | /// ``` | |
ea8adc8c | 76 | /// |
3dfed10e | 77 | /// [`Mutex`]: super::Mutex |
85aaf69f | 78 | #[stable(feature = "rust1", since = "1.0.0")] |
2b03887a | 79 | #[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")] |
d9579d0f | 80 | pub struct RwLock<T: ?Sized> { |
04454e1e | 81 | inner: sys::MovableRwLock, |
5bcae85e | 82 | poison: poison::Flag, |
1a4d82fc JJ |
83 | data: UnsafeCell<T>, |
84 | } | |
85 | ||
92a42be0 | 86 | #[stable(feature = "rust1", since = "1.0.0")] |
abe05a73 | 87 | unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} |
92a42be0 | 88 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 89 | unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} |
1a4d82fc | 90 | |
1a4d82fc JJ |
91 | /// RAII structure used to release the shared read access of a lock when |
92 | /// dropped. | |
476ff2be | 93 | /// |
cc61c64b | 94 | /// This structure is created by the [`read`] and [`try_read`] methods on |
476ff2be SL |
95 | /// [`RwLock`]. |
96 | /// | |
3dfed10e XL |
97 | /// [`read`]: RwLock::read |
98 | /// [`try_read`]: RwLock::try_read | |
94b46f34 | 99 | #[must_use = "if unused the RwLock will immediately unlock"] |
5099ac24 | 100 | #[must_not_suspend = "holding a RwLockReadGuard across suspend \ |
c295e0f8 | 101 | points can cause deadlocks, delays, \ |
5099ac24 | 102 | and cause Futures to not implement `Send`"] |
85aaf69f | 103 | #[stable(feature = "rust1", since = "1.0.0")] |
04454e1e | 104 | #[clippy::has_significant_drop] |
f2b60f7d | 105 | #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] |
d9579d0f | 106 | pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { |
064997fb FG |
107 | // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a |
108 | // `Ref` argument doesn't hold immutability for its whole scope, only until it drops. | |
109 | // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` | |
110 | // is preferable over `const* T` to allow for niche optimization. | |
111 | data: NonNull<T>, | |
112 | inner_lock: &'a sys::MovableRwLock, | |
1a4d82fc JJ |
113 | } |
114 | ||
92a42be0 | 115 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 116 | impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {} |
abe05a73 XL |
117 | |
118 | #[stable(feature = "rwlock_guard_sync", since = "1.23.0")] | |
9fa01778 | 119 | unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} |
85aaf69f | 120 | |
1a4d82fc JJ |
121 | /// RAII structure used to release the exclusive write access of a lock when |
122 | /// dropped. | |
476ff2be | 123 | /// |
cc61c64b | 124 | /// This structure is created by the [`write`] and [`try_write`] methods |
476ff2be SL |
125 | /// on [`RwLock`]. |
126 | /// | |
3dfed10e XL |
127 | /// [`write`]: RwLock::write |
128 | /// [`try_write`]: RwLock::try_write | |
94b46f34 | 129 | #[must_use = "if unused the RwLock will immediately unlock"] |
5099ac24 | 130 | #[must_not_suspend = "holding a RwLockWriteGuard across suspend \ |
c295e0f8 | 131 | points can cause deadlocks, delays, \ |
5099ac24 | 132 | and cause Future's to not implement `Send`"] |
85aaf69f | 133 | #[stable(feature = "rust1", since = "1.0.0")] |
04454e1e | 134 | #[clippy::has_significant_drop] |
f2b60f7d | 135 | #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")] |
d9579d0f | 136 | pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { |
60c5eb7d XL |
137 | lock: &'a RwLock<T>, |
138 | poison: poison::Guard, | |
1a4d82fc JJ |
139 | } |
140 | ||
92a42be0 | 141 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 142 | impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {} |
abe05a73 XL |
143 | |
144 | #[stable(feature = "rwlock_guard_sync", since = "1.23.0")] | |
9fa01778 | 145 | unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} |
85aaf69f | 146 | |
c34b1796 | 147 | impl<T> RwLock<T> { |
85aaf69f SL |
148 | /// Creates a new instance of an `RwLock<T>` which is unlocked. |
149 | /// | |
150 | /// # Examples | |
151 | /// | |
152 | /// ``` | |
153 | /// use std::sync::RwLock; | |
154 | /// | |
155 | /// let lock = RwLock::new(5); | |
156 | /// ``` | |
157 | #[stable(feature = "rust1", since = "1.0.0")] | |
923072b8 FG |
158 | #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] |
159 | #[inline] | |
160 | pub const fn new(t: T) -> RwLock<T> { | |
5bcae85e | 161 | RwLock { |
04454e1e | 162 | inner: sys::MovableRwLock::new(), |
5bcae85e SL |
163 | poison: poison::Flag::new(), |
164 | data: UnsafeCell::new(t), | |
165 | } | |
1a4d82fc | 166 | } |
d9579d0f | 167 | } |
1a4d82fc | 168 | |
d9579d0f | 169 | impl<T: ?Sized> RwLock<T> { |
2b03887a | 170 | /// Locks this `RwLock` with shared read access, blocking the current thread |
1a4d82fc JJ |
171 | /// until it can be acquired. |
172 | /// | |
173 | /// The calling thread will be blocked until there are no more writers which | |
174 | /// hold the lock. There may be other readers currently inside the lock when | |
175 | /// this method returns. This method does not provide any guarantees with | |
176 | /// respect to the ordering of whether contentious readers or writers will | |
177 | /// acquire the lock first. | |
178 | /// | |
179 | /// Returns an RAII guard which will release this thread's shared access | |
180 | /// once it is dropped. | |
181 | /// | |
7453a54e | 182 | /// # Errors |
1a4d82fc | 183 | /// |
2b03887a FG |
184 | /// This function will return an error if the `RwLock` is poisoned. An |
185 | /// `RwLock` is poisoned whenever a writer panics while holding an exclusive | |
186 | /// lock. The failure will occur immediately after the lock has been | |
187 | /// acquired. | |
c30ab7b3 SL |
188 | /// |
189 | /// # Panics | |
190 | /// | |
191 | /// This function might panic when called if the lock is already held by the current thread. | |
ea8adc8c XL |
192 | /// |
193 | /// # Examples | |
194 | /// | |
195 | /// ``` | |
196 | /// use std::sync::{Arc, RwLock}; | |
197 | /// use std::thread; | |
198 | /// | |
199 | /// let lock = Arc::new(RwLock::new(1)); | |
1b1a35ee | 200 | /// let c_lock = Arc::clone(&lock); |
ea8adc8c XL |
201 | /// |
202 | /// let n = lock.read().unwrap(); | |
203 | /// assert_eq!(*n, 1); | |
204 | /// | |
205 | /// thread::spawn(move || { | |
206 | /// let r = c_lock.read(); | |
207 | /// assert!(r.is_ok()); | |
208 | /// }).join().unwrap(); | |
209 | /// ``` | |
1a4d82fc | 210 | #[inline] |
85aaf69f | 211 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 212 | pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> { |
7453a54e | 213 | unsafe { |
5bcae85e SL |
214 | self.inner.read(); |
215 | RwLockReadGuard::new(self) | |
7453a54e | 216 | } |
1a4d82fc JJ |
217 | } |
218 | ||
2b03887a | 219 | /// Attempts to acquire this `RwLock` with shared read access. |
d9579d0f AL |
220 | /// |
221 | /// If the access could not be granted at this time, then `Err` is returned. | |
222 | /// Otherwise, an RAII guard is returned which will release the shared access | |
223 | /// when it is dropped. | |
1a4d82fc | 224 | /// |
d9579d0f AL |
225 | /// This function does not block. |
226 | /// | |
227 | /// This function does not provide any guarantees with respect to the ordering | |
228 | /// of whether contentious readers or writers will acquire the lock first. | |
1a4d82fc | 229 | /// |
7453a54e | 230 | /// # Errors |
1a4d82fc | 231 | /// |
2b03887a FG |
232 | /// This function will return the [`Poisoned`] error if the `RwLock` is |
233 | /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding | |
234 | /// an exclusive lock. `Poisoned` will only be returned if the lock would | |
235 | /// have otherwise been acquired. | |
ea8adc8c | 236 | /// |
2b03887a FG |
237 | /// This function will return the [`WouldBlock`] error if the `RwLock` could |
238 | /// not be acquired because it was already locked exclusively. | |
17df50a5 XL |
239 | /// |
240 | /// [`Poisoned`]: TryLockError::Poisoned | |
241 | /// [`WouldBlock`]: TryLockError::WouldBlock | |
242 | /// | |
ea8adc8c XL |
243 | /// # Examples |
244 | /// | |
245 | /// ``` | |
246 | /// use std::sync::RwLock; | |
247 | /// | |
248 | /// let lock = RwLock::new(1); | |
249 | /// | |
250 | /// match lock.try_read() { | |
251 | /// Ok(n) => assert_eq!(*n, 1), | |
252 | /// Err(_) => unreachable!(), | |
253 | /// }; | |
254 | /// ``` | |
1a4d82fc | 255 | #[inline] |
85aaf69f | 256 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 257 | pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> { |
7453a54e | 258 | unsafe { |
5bcae85e SL |
259 | if self.inner.try_read() { |
260 | Ok(RwLockReadGuard::new(self)?) | |
7453a54e SL |
261 | } else { |
262 | Err(TryLockError::WouldBlock) | |
263 | } | |
1a4d82fc JJ |
264 | } |
265 | } | |
266 | ||
2b03887a | 267 | /// Locks this `RwLock` with exclusive write access, blocking the current |
1a4d82fc JJ |
268 | /// thread until it can be acquired. |
269 | /// | |
270 | /// This function will not return while other writers or other readers | |
271 | /// currently have access to the lock. | |
272 | /// | |
2b03887a | 273 | /// Returns an RAII guard which will drop the write access of this `RwLock` |
1a4d82fc JJ |
274 | /// when dropped. |
275 | /// | |
7453a54e | 276 | /// # Errors |
1a4d82fc | 277 | /// |
2b03887a FG |
278 | /// This function will return an error if the `RwLock` is poisoned. An |
279 | /// `RwLock` is poisoned whenever a writer panics while holding an exclusive | |
280 | /// lock. An error will be returned when the lock is acquired. | |
c30ab7b3 SL |
281 | /// |
282 | /// # Panics | |
283 | /// | |
284 | /// This function might panic when called if the lock is already held by the current thread. | |
ea8adc8c XL |
285 | /// |
286 | /// # Examples | |
287 | /// | |
288 | /// ``` | |
289 | /// use std::sync::RwLock; | |
290 | /// | |
291 | /// let lock = RwLock::new(1); | |
292 | /// | |
293 | /// let mut n = lock.write().unwrap(); | |
294 | /// *n = 2; | |
295 | /// | |
296 | /// assert!(lock.try_read().is_err()); | |
297 | /// ``` | |
1a4d82fc | 298 | #[inline] |
85aaf69f | 299 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 300 | pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> { |
7453a54e | 301 | unsafe { |
5bcae85e SL |
302 | self.inner.write(); |
303 | RwLockWriteGuard::new(self) | |
7453a54e | 304 | } |
1a4d82fc JJ |
305 | } |
306 | ||
2b03887a | 307 | /// Attempts to lock this `RwLock` with exclusive write access. |
1a4d82fc | 308 | /// |
d9579d0f AL |
309 | /// If the lock could not be acquired at this time, then `Err` is returned. |
310 | /// Otherwise, an RAII guard is returned which will release the lock when | |
311 | /// it is dropped. | |
312 | /// | |
313 | /// This function does not block. | |
314 | /// | |
315 | /// This function does not provide any guarantees with respect to the ordering | |
316 | /// of whether contentious readers or writers will acquire the lock first. | |
1a4d82fc | 317 | /// |
7453a54e | 318 | /// # Errors |
1a4d82fc | 319 | /// |
2b03887a FG |
320 | /// This function will return the [`Poisoned`] error if the `RwLock` is |
321 | /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding | |
322 | /// an exclusive lock. `Poisoned` will only be returned if the lock would | |
323 | /// have otherwise been acquired. | |
17df50a5 | 324 | /// |
2b03887a FG |
325 | /// This function will return the [`WouldBlock`] error if the `RwLock` could |
326 | /// not be acquired because it was already locked exclusively. | |
17df50a5 XL |
327 | /// |
328 | /// [`Poisoned`]: TryLockError::Poisoned | |
329 | /// [`WouldBlock`]: TryLockError::WouldBlock | |
330 | /// | |
ea8adc8c XL |
331 | /// |
332 | /// # Examples | |
333 | /// | |
334 | /// ``` | |
335 | /// use std::sync::RwLock; | |
336 | /// | |
337 | /// let lock = RwLock::new(1); | |
338 | /// | |
339 | /// let n = lock.read().unwrap(); | |
340 | /// assert_eq!(*n, 1); | |
341 | /// | |
342 | /// assert!(lock.try_write().is_err()); | |
343 | /// ``` | |
1a4d82fc | 344 | #[inline] |
85aaf69f | 345 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 346 | pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> { |
7453a54e | 347 | unsafe { |
5bcae85e SL |
348 | if self.inner.try_write() { |
349 | Ok(RwLockWriteGuard::new(self)?) | |
7453a54e SL |
350 | } else { |
351 | Err(TryLockError::WouldBlock) | |
352 | } | |
1a4d82fc JJ |
353 | } |
354 | } | |
85aaf69f | 355 | |
9346a6ac | 356 | /// Determines whether the lock is poisoned. |
85aaf69f SL |
357 | /// |
358 | /// If another thread is active, the lock can still become poisoned at any | |
9fa01778 | 359 | /// time. You should not trust a `false` value for program correctness |
85aaf69f | 360 | /// without additional synchronization. |
ea8adc8c XL |
361 | /// |
362 | /// # Examples | |
363 | /// | |
364 | /// ``` | |
365 | /// use std::sync::{Arc, RwLock}; | |
366 | /// use std::thread; | |
367 | /// | |
368 | /// let lock = Arc::new(RwLock::new(0)); | |
1b1a35ee | 369 | /// let c_lock = Arc::clone(&lock); |
ea8adc8c XL |
370 | /// |
371 | /// let _ = thread::spawn(move || { | |
372 | /// let _lock = c_lock.write().unwrap(); | |
373 | /// panic!(); // the lock gets poisoned | |
374 | /// }).join(); | |
375 | /// assert_eq!(lock.is_poisoned(), true); | |
376 | /// ``` | |
85aaf69f | 377 | #[inline] |
62682a34 | 378 | #[stable(feature = "sync_poison", since = "1.2.0")] |
85aaf69f | 379 | pub fn is_poisoned(&self) -> bool { |
5bcae85e | 380 | self.poison.get() |
85aaf69f | 381 | } |
b039eaaf | 382 | |
923072b8 FG |
383 | /// Clear the poisoned state from a lock |
384 | /// | |
385 | /// If the lock is poisoned, it will remain poisoned until this function is called. This allows | |
386 | /// recovering from a poisoned state and marking that it has recovered. For example, if the | |
387 | /// value is overwritten by a known-good value, then the mutex can be marked as un-poisoned. Or | |
388 | /// possibly, the value could be inspected to determine if it is in a consistent state, and if | |
389 | /// so the poison is removed. | |
390 | /// | |
391 | /// # Examples | |
392 | /// | |
393 | /// ``` | |
394 | /// #![feature(mutex_unpoison)] | |
395 | /// | |
396 | /// use std::sync::{Arc, RwLock}; | |
397 | /// use std::thread; | |
398 | /// | |
399 | /// let lock = Arc::new(RwLock::new(0)); | |
400 | /// let c_lock = Arc::clone(&lock); | |
401 | /// | |
402 | /// let _ = thread::spawn(move || { | |
403 | /// let _lock = c_lock.write().unwrap(); | |
404 | /// panic!(); // the mutex gets poisoned | |
405 | /// }).join(); | |
406 | /// | |
407 | /// assert_eq!(lock.is_poisoned(), true); | |
408 | /// let guard = lock.write().unwrap_or_else(|mut e| { | |
409 | /// **e.get_mut() = 1; | |
410 | /// lock.clear_poison(); | |
411 | /// e.into_inner() | |
412 | /// }); | |
413 | /// assert_eq!(lock.is_poisoned(), false); | |
414 | /// assert_eq!(*guard, 1); | |
415 | /// ``` | |
416 | #[inline] | |
417 | #[unstable(feature = "mutex_unpoison", issue = "96469")] | |
418 | pub fn clear_poison(&self) { | |
419 | self.poison.clear(); | |
420 | } | |
421 | ||
b039eaaf SL |
422 | /// Consumes this `RwLock`, returning the underlying data. |
423 | /// | |
7453a54e | 424 | /// # Errors |
b039eaaf | 425 | /// |
2b03887a FG |
426 | /// This function will return an error if the `RwLock` is poisoned. An |
427 | /// `RwLock` is poisoned whenever a writer panics while holding an exclusive | |
428 | /// lock. An error will only be returned if the lock would have otherwise | |
429 | /// been acquired. | |
ea8adc8c XL |
430 | /// |
431 | /// # Examples | |
432 | /// | |
433 | /// ``` | |
434 | /// use std::sync::RwLock; | |
435 | /// | |
436 | /// let lock = RwLock::new(String::new()); | |
437 | /// { | |
438 | /// let mut s = lock.write().unwrap(); | |
439 | /// *s = "modified".to_owned(); | |
440 | /// } | |
441 | /// assert_eq!(lock.into_inner().unwrap(), "modified"); | |
442 | /// ``` | |
92a42be0 | 443 | #[stable(feature = "rwlock_into_inner", since = "1.6.0")] |
dfeec247 XL |
444 | pub fn into_inner(self) -> LockResult<T> |
445 | where | |
446 | T: Sized, | |
447 | { | |
17df50a5 | 448 | let data = self.data.into_inner(); |
923072b8 | 449 | poison::map_result(self.poison.borrow(), |()| data) |
b039eaaf SL |
450 | } |
451 | ||
452 | /// Returns a mutable reference to the underlying data. | |
453 | /// | |
454 | /// Since this call borrows the `RwLock` mutably, no actual locking needs to | |
9fa01778 | 455 | /// take place -- the mutable borrow statically guarantees no locks exist. |
b039eaaf | 456 | /// |
7453a54e | 457 | /// # Errors |
b039eaaf | 458 | /// |
2b03887a FG |
459 | /// This function will return an error if the `RwLock` is poisoned. An |
460 | /// `RwLock` is poisoned whenever a writer panics while holding an exclusive | |
461 | /// lock. An error will only be returned if the lock would have otherwise | |
462 | /// been acquired. | |
ea8adc8c XL |
463 | /// |
464 | /// # Examples | |
465 | /// | |
466 | /// ``` | |
467 | /// use std::sync::RwLock; | |
468 | /// | |
469 | /// let mut lock = RwLock::new(0); | |
470 | /// *lock.get_mut().unwrap() = 10; | |
471 | /// assert_eq!(*lock.read().unwrap(), 10); | |
472 | /// ``` | |
92a42be0 | 473 | #[stable(feature = "rwlock_get_mut", since = "1.6.0")] |
b039eaaf | 474 | pub fn get_mut(&mut self) -> LockResult<&mut T> { |
1b1a35ee | 475 | let data = self.data.get_mut(); |
923072b8 | 476 | poison::map_result(self.poison.borrow(), |()| data) |
b039eaaf | 477 | } |
1a4d82fc JJ |
478 | } |
479 | ||
c34b1796 | 480 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 481 | impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { |
532ac7d7 | 482 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 483 | let mut d = f.debug_struct("RwLock"); |
c34b1796 | 484 | match self.try_read() { |
cdc7bbd5 XL |
485 | Ok(guard) => { |
486 | d.field("data", &&*guard); | |
487 | } | |
c34b1796 | 488 | Err(TryLockError::Poisoned(err)) => { |
cdc7bbd5 | 489 | d.field("data", &&**err.get_ref()); |
dfeec247 | 490 | } |
abe05a73 XL |
491 | Err(TryLockError::WouldBlock) => { |
492 | struct LockedPlaceholder; | |
493 | impl fmt::Debug for LockedPlaceholder { | |
532ac7d7 XL |
494 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
495 | f.write_str("<locked>") | |
496 | } | |
abe05a73 | 497 | } |
cdc7bbd5 | 498 | d.field("data", &LockedPlaceholder); |
abe05a73 | 499 | } |
c34b1796 | 500 | } |
cdc7bbd5 XL |
501 | d.field("poisoned", &self.poison.get()); |
502 | d.finish_non_exhaustive() | |
c34b1796 AL |
503 | } |
504 | } | |
505 | ||
7cac9316 | 506 | #[stable(feature = "rw_lock_default", since = "1.10.0")] |
a7813a04 | 507 | impl<T: Default> Default for RwLock<T> { |
9e0c209e | 508 | /// Creates a new `RwLock<T>`, with the `Default` value for T. |
a7813a04 XL |
509 | fn default() -> RwLock<T> { |
510 | RwLock::new(Default::default()) | |
511 | } | |
512 | } | |
513 | ||
2c00a5a8 | 514 | #[stable(feature = "rw_lock_from", since = "1.24.0")] |
ff7c6d11 XL |
515 | impl<T> From<T> for RwLock<T> { |
516 | /// Creates a new instance of an `RwLock<T>` which is unlocked. | |
517 | /// This is equivalent to [`RwLock::new`]. | |
ff7c6d11 XL |
518 | fn from(t: T) -> Self { |
519 | RwLock::new(t) | |
520 | } | |
521 | } | |
522 | ||
d9579d0f | 523 | impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { |
064997fb FG |
524 | /// Create a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`. |
525 | // SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been | |
526 | // successfully called from the same thread before instantiating this object. | |
dfeec247 | 527 | unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> { |
064997fb FG |
528 | poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { |
529 | data: NonNull::new_unchecked(lock.data.get()), | |
530 | inner_lock: &lock.inner, | |
531 | }) | |
1a4d82fc JJ |
532 | } |
533 | } | |
85aaf69f | 534 | |
d9579d0f | 535 | impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { |
064997fb FG |
536 | /// Create a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. |
537 | // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been | |
538 | // successfully called from the same thread before instantiating this object. | |
dfeec247 | 539 | unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { |
923072b8 | 540 | poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) |
1a4d82fc JJ |
541 | } |
542 | } | |
543 | ||
8bb4bdeb | 544 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 545 | impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { |
532ac7d7 | 546 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 547 | (**self).fmt(f) |
32a655c1 SL |
548 | } |
549 | } | |
550 | ||
041b39d2 | 551 | #[stable(feature = "std_guard_impls", since = "1.20.0")] |
9fa01778 | 552 | impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { |
532ac7d7 | 553 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
554 | (**self).fmt(f) |
555 | } | |
556 | } | |
557 | ||
8bb4bdeb | 558 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 559 | impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { |
532ac7d7 | 560 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 561 | (**self).fmt(f) |
32a655c1 SL |
562 | } |
563 | } | |
564 | ||
041b39d2 | 565 | #[stable(feature = "std_guard_impls", since = "1.20.0")] |
9fa01778 | 566 | impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { |
532ac7d7 | 567 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
568 | (**self).fmt(f) |
569 | } | |
570 | } | |
571 | ||
85aaf69f | 572 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 573 | impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { |
1a4d82fc JJ |
574 | type Target = T; |
575 | ||
5bcae85e | 576 | fn deref(&self) -> &T { |
064997fb FG |
577 | // SAFETY: the conditions of `RwLockGuard::new` were satisfied when created. |
578 | unsafe { self.data.as_ref() } | |
5bcae85e | 579 | } |
1a4d82fc | 580 | } |
d9579d0f | 581 | |
85aaf69f | 582 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 583 | impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { |
1a4d82fc JJ |
584 | type Target = T; |
585 | ||
5bcae85e | 586 | fn deref(&self) -> &T { |
064997fb | 587 | // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. |
60c5eb7d | 588 | unsafe { &*self.lock.data.get() } |
5bcae85e | 589 | } |
1a4d82fc | 590 | } |
d9579d0f | 591 | |
85aaf69f | 592 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 593 | impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { |
a7813a04 | 594 | fn deref_mut(&mut self) -> &mut T { |
064997fb | 595 | // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. |
60c5eb7d | 596 | unsafe { &mut *self.lock.data.get() } |
1a4d82fc JJ |
597 | } |
598 | } | |
599 | ||
85aaf69f | 600 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 601 | impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { |
1a4d82fc | 602 | fn drop(&mut self) { |
064997fb | 603 | // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. |
dfeec247 | 604 | unsafe { |
064997fb | 605 | self.inner_lock.read_unlock(); |
dfeec247 | 606 | } |
1a4d82fc JJ |
607 | } |
608 | } | |
609 | ||
85aaf69f | 610 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 611 | impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { |
1a4d82fc | 612 | fn drop(&mut self) { |
60c5eb7d | 613 | self.lock.poison.done(&self.poison); |
064997fb | 614 | // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. |
dfeec247 XL |
615 | unsafe { |
616 | self.lock.inner.write_unlock(); | |
617 | } | |
1a4d82fc JJ |
618 | } |
619 | } |