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