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