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