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