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