]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/rwlock.rs
Rollup merge of #40521 - TimNN:panic-free-shift, r=alexcrichton
[rust.git] / src / libstd / sync / rwlock.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use cell::UnsafeCell;
12 use fmt;
13 use marker;
14 use mem;
15 use ops::{Deref, DerefMut};
16 use ptr;
17 use sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
18 use sys_common::rwlock as sys;
19
20 /// A reader-writer lock
21 ///
22 /// This type of lock allows a number of readers or at most one writer at any
23 /// point in time. The write portion of this lock typically allows modification
24 /// of the underlying data (exclusive access) and the read portion of this lock
25 /// typically allows for read-only access (shared access).
26 ///
27 /// The priority policy of the lock is dependent on the underlying operating
28 /// system's implementation, and this type does not guarantee that any
29 /// particular policy will be used.
30 ///
31 /// The type parameter `T` represents the data that this lock protects. It is
32 /// required that `T` satisfies `Send` to be shared across threads and `Sync` to
33 /// allow concurrent access through readers. The RAII guards returned from the
34 /// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
35 /// to allow access to the contained of the lock.
36 ///
37 /// # Poisoning
38 ///
39 /// An `RwLock`, like `Mutex`, will become poisoned on a panic. Note, however,
40 /// that an `RwLock` may only be poisoned if a panic occurs while it is locked
41 /// exclusively (write mode). If a panic occurs in any reader, then the lock
42 /// will not be poisoned.
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// use std::sync::RwLock;
48 ///
49 /// let lock = RwLock::new(5);
50 ///
51 /// // many reader locks can be held at once
52 /// {
53 ///     let r1 = lock.read().unwrap();
54 ///     let r2 = lock.read().unwrap();
55 ///     assert_eq!(*r1, 5);
56 ///     assert_eq!(*r2, 5);
57 /// } // read locks are dropped at this point
58 ///
59 /// // only one write lock may be held, however
60 /// {
61 ///     let mut w = lock.write().unwrap();
62 ///     *w += 1;
63 ///     assert_eq!(*w, 6);
64 /// } // write lock is dropped here
65 /// ```
66 #[stable(feature = "rust1", since = "1.0.0")]
67 pub struct RwLock<T: ?Sized> {
68     inner: Box<sys::RWLock>,
69     poison: poison::Flag,
70     data: UnsafeCell<T>,
71 }
72
73 #[stable(feature = "rust1", since = "1.0.0")]
74 unsafe impl<T: ?Sized + Send + Sync> Send for RwLock<T> {}
75 #[stable(feature = "rust1", since = "1.0.0")]
76 unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
77
78 /// RAII structure used to release the shared read access of a lock when
79 /// dropped.
80 ///
81 /// This structure is created by the [`read`] and [`try_read`] methods on
82 /// [`RwLock`].
83 ///
84 /// [`read`]: struct.RwLock.html#method.read
85 /// [`try_read`]: struct.RwLock.html#method.try_read
86 /// [`RwLock`]: struct.RwLock.html
87 #[must_use]
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<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {}
95
96 /// RAII structure used to release the exclusive write access of a lock when
97 /// dropped.
98 ///
99 /// This structure is created by the [`write`] and [`try_write`] methods
100 /// on [`RwLock`].
101 ///
102 /// [`write`]: struct.RwLock.html#method.write
103 /// [`try_write`]: struct.RwLock.html#method.try_write
104 /// [`RwLock`]: struct.RwLock.html
105 #[must_use]
106 #[stable(feature = "rust1", since = "1.0.0")]
107 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
108     __lock: &'a RwLock<T>,
109     __poison: poison::Guard,
110 }
111
112 #[stable(feature = "rust1", since = "1.0.0")]
113 impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {}
114
115 impl<T> RwLock<T> {
116     /// Creates a new instance of an `RwLock<T>` which is unlocked.
117     ///
118     /// # Examples
119     ///
120     /// ```
121     /// use std::sync::RwLock;
122     ///
123     /// let lock = RwLock::new(5);
124     /// ```
125     #[stable(feature = "rust1", since = "1.0.0")]
126     pub fn new(t: T) -> RwLock<T> {
127         RwLock {
128             inner: box sys::RWLock::new(),
129             poison: poison::Flag::new(),
130             data: UnsafeCell::new(t),
131         }
132     }
133 }
134
135 impl<T: ?Sized> RwLock<T> {
136     /// Locks this rwlock with shared read access, blocking the current thread
137     /// until it can be acquired.
138     ///
139     /// The calling thread will be blocked until there are no more writers which
140     /// hold the lock. There may be other readers currently inside the lock when
141     /// this method returns. This method does not provide any guarantees with
142     /// respect to the ordering of whether contentious readers or writers will
143     /// acquire the lock first.
144     ///
145     /// Returns an RAII guard which will release this thread's shared access
146     /// once it is dropped.
147     ///
148     /// # Errors
149     ///
150     /// This function will return an error if the RwLock is poisoned. An RwLock
151     /// is poisoned whenever a writer panics while holding an exclusive lock.
152     /// The failure will occur immediately after the lock has been acquired.
153     ///
154     /// # Panics
155     ///
156     /// This function might panic when called if the lock is already held by the current thread.
157     #[inline]
158     #[stable(feature = "rust1", since = "1.0.0")]
159     pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
160         unsafe {
161             self.inner.read();
162             RwLockReadGuard::new(self)
163         }
164     }
165
166     /// Attempts to acquire this rwlock with shared read access.
167     ///
168     /// If the access could not be granted at this time, then `Err` is returned.
169     /// Otherwise, an RAII guard is returned which will release the shared access
170     /// when it is dropped.
171     ///
172     /// This function does not block.
173     ///
174     /// This function does not provide any guarantees with respect to the ordering
175     /// of whether contentious readers or writers will acquire the lock first.
176     ///
177     /// # Errors
178     ///
179     /// This function will return an error if the RwLock is poisoned. An RwLock
180     /// is poisoned whenever a writer panics while holding an exclusive lock. An
181     /// error will only be returned if the lock would have otherwise been
182     /// acquired.
183     #[inline]
184     #[stable(feature = "rust1", since = "1.0.0")]
185     pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<T>> {
186         unsafe {
187             if self.inner.try_read() {
188                 Ok(RwLockReadGuard::new(self)?)
189             } else {
190                 Err(TryLockError::WouldBlock)
191             }
192         }
193     }
194
195     /// Locks this rwlock with exclusive write access, blocking the current
196     /// thread until it can be acquired.
197     ///
198     /// This function will not return while other writers or other readers
199     /// currently have access to the lock.
200     ///
201     /// Returns an RAII guard which will drop the write access of this rwlock
202     /// when dropped.
203     ///
204     /// # Errors
205     ///
206     /// This function will return an error if the RwLock is poisoned. An RwLock
207     /// is poisoned whenever a writer panics while holding an exclusive lock.
208     /// An error will be returned when the lock is acquired.
209     ///
210     /// # Panics
211     ///
212     /// This function might panic when called if the lock is already held by the current thread.
213     #[inline]
214     #[stable(feature = "rust1", since = "1.0.0")]
215     pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
216         unsafe {
217             self.inner.write();
218             RwLockWriteGuard::new(self)
219         }
220     }
221
222     /// Attempts to lock this rwlock with exclusive write access.
223     ///
224     /// If the lock could not be acquired at this time, then `Err` is returned.
225     /// Otherwise, an RAII guard is returned which will release the lock when
226     /// it is dropped.
227     ///
228     /// This function does not block.
229     ///
230     /// This function does not provide any guarantees with respect to the ordering
231     /// of whether contentious readers or writers will acquire the lock first.
232     ///
233     /// # Errors
234     ///
235     /// This function will return an error if the RwLock is poisoned. An RwLock
236     /// is poisoned whenever a writer panics while holding an exclusive lock. An
237     /// error will only be returned if the lock would have otherwise been
238     /// acquired.
239     #[inline]
240     #[stable(feature = "rust1", since = "1.0.0")]
241     pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<T>> {
242         unsafe {
243             if self.inner.try_write() {
244                 Ok(RwLockWriteGuard::new(self)?)
245             } else {
246                 Err(TryLockError::WouldBlock)
247             }
248         }
249     }
250
251     /// Determines whether the lock is poisoned.
252     ///
253     /// If another thread is active, the lock can still become poisoned at any
254     /// time.  You should not trust a `false` value for program correctness
255     /// without additional synchronization.
256     #[inline]
257     #[stable(feature = "sync_poison", since = "1.2.0")]
258     pub fn is_poisoned(&self) -> bool {
259         self.poison.get()
260     }
261
262     /// Consumes this `RwLock`, returning the underlying data.
263     ///
264     /// # Errors
265     ///
266     /// This function will return an error if the RwLock is poisoned. An RwLock
267     /// is poisoned whenever a writer panics while holding an exclusive lock. An
268     /// error will only be returned if the lock would have otherwise been
269     /// acquired.
270     #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
271     pub fn into_inner(self) -> LockResult<T> where T: Sized {
272         // We know statically that there are no outstanding references to
273         // `self` so there's no need to lock the inner lock.
274         //
275         // To get the inner value, we'd like to call `data.into_inner()`,
276         // but because `RwLock` impl-s `Drop`, we can't move out of it, so
277         // we'll have to destructure it manually instead.
278         unsafe {
279             // Like `let RwLock { inner, poison, data } = self`.
280             let (inner, poison, data) = {
281                 let RwLock { ref inner, ref poison, ref data } = self;
282                 (ptr::read(inner), ptr::read(poison), ptr::read(data))
283             };
284             mem::forget(self);
285             inner.destroy();  // Keep in sync with the `Drop` impl.
286             drop(inner);
287
288             poison::map_result(poison.borrow(), |_| data.into_inner())
289         }
290     }
291
292     /// Returns a mutable reference to the underlying data.
293     ///
294     /// Since this call borrows the `RwLock` mutably, no actual locking needs to
295     /// take place---the mutable borrow statically guarantees no locks exist.
296     ///
297     /// # Errors
298     ///
299     /// This function will return an error if the RwLock is poisoned. An RwLock
300     /// is poisoned whenever a writer panics while holding an exclusive lock. An
301     /// error will only be returned if the lock would have otherwise been
302     /// acquired.
303     #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
304     pub fn get_mut(&mut self) -> LockResult<&mut T> {
305         // We know statically that there are no other references to `self`, so
306         // there's no need to lock the inner lock.
307         let data = unsafe { &mut *self.data.get() };
308         poison::map_result(self.poison.borrow(), |_| data)
309     }
310 }
311
312 #[stable(feature = "rust1", since = "1.0.0")]
313 unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
314     fn drop(&mut self) {
315         // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
316         unsafe { self.inner.destroy() }
317     }
318 }
319
320 #[stable(feature = "rust1", since = "1.0.0")]
321 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
322     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323         match self.try_read() {
324             Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
325             Err(TryLockError::Poisoned(err)) => {
326                 write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref())
327             },
328             Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ <locked> }}")
329         }
330     }
331 }
332
333 #[stable(feature = "rw_lock_default", since = "1.9.0")]
334 impl<T: Default> Default for RwLock<T> {
335     /// Creates a new `RwLock<T>`, with the `Default` value for T.
336     fn default() -> RwLock<T> {
337         RwLock::new(Default::default())
338     }
339 }
340
341 impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
342     unsafe fn new(lock: &'rwlock RwLock<T>)
343                   -> LockResult<RwLockReadGuard<'rwlock, T>> {
344         poison::map_result(lock.poison.borrow(), |_| {
345             RwLockReadGuard {
346                 __lock: lock,
347             }
348         })
349     }
350 }
351
352 impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
353     unsafe fn new(lock: &'rwlock RwLock<T>)
354                   -> LockResult<RwLockWriteGuard<'rwlock, T>> {
355         poison::map_result(lock.poison.borrow(), |guard| {
356             RwLockWriteGuard {
357                 __lock: lock,
358                 __poison: guard,
359             }
360         })
361     }
362 }
363
364 #[stable(feature = "std_debug", since = "1.16.0")]
365 impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> {
366     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367         f.debug_struct("RwLockReadGuard")
368             .field("lock", &self.__lock)
369             .finish()
370     }
371 }
372
373 #[stable(feature = "std_debug", since = "1.16.0")]
374 impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> {
375     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376         f.debug_struct("RwLockWriteGuard")
377             .field("lock", &self.__lock)
378             .finish()
379     }
380 }
381
382 #[stable(feature = "rust1", since = "1.0.0")]
383 impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
384     type Target = T;
385
386     fn deref(&self) -> &T {
387         unsafe { &*self.__lock.data.get() }
388     }
389 }
390
391 #[stable(feature = "rust1", since = "1.0.0")]
392 impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> {
393     type Target = T;
394
395     fn deref(&self) -> &T {
396         unsafe { &*self.__lock.data.get() }
397     }
398 }
399
400 #[stable(feature = "rust1", since = "1.0.0")]
401 impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> {
402     fn deref_mut(&mut self) -> &mut T {
403         unsafe { &mut *self.__lock.data.get() }
404     }
405 }
406
407 #[stable(feature = "rust1", since = "1.0.0")]
408 impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> {
409     fn drop(&mut self) {
410         unsafe { self.__lock.inner.read_unlock(); }
411     }
412 }
413
414 #[stable(feature = "rust1", since = "1.0.0")]
415 impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> {
416     fn drop(&mut self) {
417         self.__lock.poison.done(&self.__poison);
418         unsafe { self.__lock.inner.write_unlock(); }
419     }
420 }
421
422 #[cfg(all(test, not(target_os = "emscripten")))]
423 mod tests {
424     #![allow(deprecated)] // rand
425
426     use rand::{self, Rng};
427     use sync::mpsc::channel;
428     use thread;
429     use sync::{Arc, RwLock, TryLockError};
430     use sync::atomic::{AtomicUsize, Ordering};
431
432     #[derive(Eq, PartialEq, Debug)]
433     struct NonCopy(i32);
434
435     #[test]
436     fn smoke() {
437         let l = RwLock::new(());
438         drop(l.read().unwrap());
439         drop(l.write().unwrap());
440         drop((l.read().unwrap(), l.read().unwrap()));
441         drop(l.write().unwrap());
442     }
443
444     #[test]
445     fn frob() {
446         const N: usize = 10;
447         const M: usize = 1000;
448
449         let r = Arc::new(RwLock::new(()));
450
451         let (tx, rx) = channel::<()>();
452         for _ in 0..N {
453             let tx = tx.clone();
454             let r = r.clone();
455             thread::spawn(move || {
456                 let mut rng = rand::thread_rng();
457                 for _ in 0..M {
458                     if rng.gen_weighted_bool(N) {
459                         drop(r.write().unwrap());
460                     } else {
461                         drop(r.read().unwrap());
462                     }
463                 }
464                 drop(tx);
465             });
466         }
467         drop(tx);
468         let _ = rx.recv();
469     }
470
471     #[test]
472     fn test_rw_arc_poison_wr() {
473         let arc = Arc::new(RwLock::new(1));
474         let arc2 = arc.clone();
475         let _: Result<(), _> = thread::spawn(move|| {
476             let _lock = arc2.write().unwrap();
477             panic!();
478         }).join();
479         assert!(arc.read().is_err());
480     }
481
482     #[test]
483     fn test_rw_arc_poison_ww() {
484         let arc = Arc::new(RwLock::new(1));
485         assert!(!arc.is_poisoned());
486         let arc2 = arc.clone();
487         let _: Result<(), _> = thread::spawn(move|| {
488             let _lock = arc2.write().unwrap();
489             panic!();
490         }).join();
491         assert!(arc.write().is_err());
492         assert!(arc.is_poisoned());
493     }
494
495     #[test]
496     fn test_rw_arc_no_poison_rr() {
497         let arc = Arc::new(RwLock::new(1));
498         let arc2 = arc.clone();
499         let _: Result<(), _> = thread::spawn(move|| {
500             let _lock = arc2.read().unwrap();
501             panic!();
502         }).join();
503         let lock = arc.read().unwrap();
504         assert_eq!(*lock, 1);
505     }
506     #[test]
507     fn test_rw_arc_no_poison_rw() {
508         let arc = Arc::new(RwLock::new(1));
509         let arc2 = arc.clone();
510         let _: Result<(), _> = thread::spawn(move|| {
511             let _lock = arc2.read().unwrap();
512             panic!()
513         }).join();
514         let lock = arc.write().unwrap();
515         assert_eq!(*lock, 1);
516     }
517
518     #[test]
519     fn test_rw_arc() {
520         let arc = Arc::new(RwLock::new(0));
521         let arc2 = arc.clone();
522         let (tx, rx) = channel();
523
524         thread::spawn(move|| {
525             let mut lock = arc2.write().unwrap();
526             for _ in 0..10 {
527                 let tmp = *lock;
528                 *lock = -1;
529                 thread::yield_now();
530                 *lock = tmp + 1;
531             }
532             tx.send(()).unwrap();
533         });
534
535         // Readers try to catch the writer in the act
536         let mut children = Vec::new();
537         for _ in 0..5 {
538             let arc3 = arc.clone();
539             children.push(thread::spawn(move|| {
540                 let lock = arc3.read().unwrap();
541                 assert!(*lock >= 0);
542             }));
543         }
544
545         // Wait for children to pass their asserts
546         for r in children {
547             assert!(r.join().is_ok());
548         }
549
550         // Wait for writer to finish
551         rx.recv().unwrap();
552         let lock = arc.read().unwrap();
553         assert_eq!(*lock, 10);
554     }
555
556     #[test]
557     fn test_rw_arc_access_in_unwind() {
558         let arc = Arc::new(RwLock::new(1));
559         let arc2 = arc.clone();
560         let _ = thread::spawn(move|| -> () {
561             struct Unwinder {
562                 i: Arc<RwLock<isize>>,
563             }
564             impl Drop for Unwinder {
565                 fn drop(&mut self) {
566                     let mut lock = self.i.write().unwrap();
567                     *lock += 1;
568                 }
569             }
570             let _u = Unwinder { i: arc2 };
571             panic!();
572         }).join();
573         let lock = arc.read().unwrap();
574         assert_eq!(*lock, 2);
575     }
576
577     #[test]
578     fn test_rwlock_unsized() {
579         let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
580         {
581             let b = &mut *rw.write().unwrap();
582             b[0] = 4;
583             b[2] = 5;
584         }
585         let comp: &[i32] = &[4, 2, 5];
586         assert_eq!(&*rw.read().unwrap(), comp);
587     }
588
589     #[test]
590     fn test_rwlock_try_write() {
591         let lock = RwLock::new(0isize);
592         let read_guard = lock.read().unwrap();
593
594         let write_result = lock.try_write();
595         match write_result {
596             Err(TryLockError::WouldBlock) => (),
597             Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
598             Err(_) => assert!(false, "unexpected error"),
599         }
600
601         drop(read_guard);
602     }
603
604     #[test]
605     fn test_into_inner() {
606         let m = RwLock::new(NonCopy(10));
607         assert_eq!(m.into_inner().unwrap(), NonCopy(10));
608     }
609
610     #[test]
611     fn test_into_inner_drop() {
612         struct Foo(Arc<AtomicUsize>);
613         impl Drop for Foo {
614             fn drop(&mut self) {
615                 self.0.fetch_add(1, Ordering::SeqCst);
616             }
617         }
618         let num_drops = Arc::new(AtomicUsize::new(0));
619         let m = RwLock::new(Foo(num_drops.clone()));
620         assert_eq!(num_drops.load(Ordering::SeqCst), 0);
621         {
622             let _inner = m.into_inner().unwrap();
623             assert_eq!(num_drops.load(Ordering::SeqCst), 0);
624         }
625         assert_eq!(num_drops.load(Ordering::SeqCst), 1);
626     }
627
628     #[test]
629     fn test_into_inner_poison() {
630         let m = Arc::new(RwLock::new(NonCopy(10)));
631         let m2 = m.clone();
632         let _ = thread::spawn(move || {
633             let _lock = m2.write().unwrap();
634             panic!("test panic in inner thread to poison RwLock");
635         }).join();
636
637         assert!(m.is_poisoned());
638         match Arc::try_unwrap(m).unwrap().into_inner() {
639             Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
640             Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
641         }
642     }
643
644     #[test]
645     fn test_get_mut() {
646         let mut m = RwLock::new(NonCopy(10));
647         *m.get_mut().unwrap() = NonCopy(20);
648         assert_eq!(m.into_inner().unwrap(), NonCopy(20));
649     }
650
651     #[test]
652     fn test_get_mut_poison() {
653         let m = Arc::new(RwLock::new(NonCopy(10)));
654         let m2 = m.clone();
655         let _ = thread::spawn(move || {
656             let _lock = m2.write().unwrap();
657             panic!("test panic in inner thread to poison RwLock");
658         }).join();
659
660         assert!(m.is_poisoned());
661         match Arc::try_unwrap(m).unwrap().get_mut() {
662             Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
663             Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
664         }
665     }
666 }