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