aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sync/rwlock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ctr-std/src/sync/rwlock.rs')
-rw-r--r--ctr-std/src/sync/rwlock.rs808
1 files changed, 0 insertions, 808 deletions
diff --git a/ctr-std/src/sync/rwlock.rs b/ctr-std/src/sync/rwlock.rs
deleted file mode 100644
index e3db60c..0000000
--- a/ctr-std/src/sync/rwlock.rs
+++ /dev/null
@@ -1,808 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cell::UnsafeCell;
-use fmt;
-use mem;
-use ops::{Deref, DerefMut};
-use ptr;
-use sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
-use sys_common::rwlock as sys;
-
-/// A reader-writer lock
-///
-/// This type of lock allows a number of readers or at most one writer at any
-/// point in time. The write portion of this lock typically allows modification
-/// of the underlying data (exclusive access) and the read portion of this lock
-/// typically allows for read-only access (shared access).
-///
-/// In comparison, a [`Mutex`] does not distinguish between readers or writers
-/// that acquire the lock, therefore blocking any threads waiting for the lock to
-/// become available. An `RwLock` will allow any number of readers to acquire the
-/// lock as long as a writer is not holding the lock.
-///
-/// The priority policy of the lock is dependent on the underlying operating
-/// system's implementation, and this type does not guarantee that any
-/// particular policy will be used.
-///
-/// The type parameter `T` represents the data that this lock protects. It is
-/// required that `T` satisfies [`Send`] to be shared across threads and
-/// [`Sync`] to allow concurrent access through readers. The RAII guards
-/// returned from the locking methods implement [`Deref`][] (and [`DerefMut`]
-/// for the `write` methods) to allow access to the content of the lock.
-///
-/// # Poisoning
-///
-/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
-/// that an `RwLock` may only be poisoned if a panic occurs while it is locked
-/// exclusively (write mode). If a panic occurs in any reader, then the lock
-/// will not be poisoned.
-///
-/// # Examples
-///
-/// ```
-/// use std::sync::RwLock;
-///
-/// let lock = RwLock::new(5);
-///
-/// // many reader locks can be held at once
-/// {
-/// let r1 = lock.read().unwrap();
-/// let r2 = lock.read().unwrap();
-/// assert_eq!(*r1, 5);
-/// assert_eq!(*r2, 5);
-/// } // read locks are dropped at this point
-///
-/// // only one write lock may be held, however
-/// {
-/// let mut w = lock.write().unwrap();
-/// *w += 1;
-/// assert_eq!(*w, 6);
-/// } // write lock is dropped here
-/// ```
-///
-/// [`Deref`]: ../../std/ops/trait.Deref.html
-/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
-/// [`Send`]: ../../std/marker/trait.Send.html
-/// [`Sync`]: ../../std/marker/trait.Sync.html
-/// [`Mutex`]: struct.Mutex.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RwLock<T: ?Sized> {
- inner: Box<sys::RWLock>,
- poison: poison::Flag,
- data: UnsafeCell<T>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
-
-/// RAII structure used to release the shared read access of a lock when
-/// dropped.
-///
-/// This structure is created by the [`read`] and [`try_read`] methods on
-/// [`RwLock`].
-///
-/// [`read`]: struct.RwLock.html#method.read
-/// [`try_read`]: struct.RwLock.html#method.try_read
-/// [`RwLock`]: struct.RwLock.html
-#[must_use = "if unused the RwLock will immediately unlock"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> !Send for RwLockReadGuard<'a, T> {}
-
-#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
-unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {}
-
-/// RAII structure used to release the exclusive write access of a lock when
-/// dropped.
-///
-/// This structure is created by the [`write`] and [`try_write`] methods
-/// on [`RwLock`].
-///
-/// [`write`]: struct.RwLock.html#method.write
-/// [`try_write`]: struct.RwLock.html#method.try_write
-/// [`RwLock`]: struct.RwLock.html
-#[must_use = "if unused the RwLock will immediately unlock"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
- __poison: poison::Guard,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> !Send for RwLockWriteGuard<'a, T> {}
-
-#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
-unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockWriteGuard<'a, T> {}
-
-impl<T> RwLock<T> {
- /// Creates a new instance of an `RwLock<T>` which is unlocked.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let lock = RwLock::new(5);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(t: T) -> RwLock<T> {
- RwLock {
- inner: box sys::RWLock::new(),
- poison: poison::Flag::new(),
- data: UnsafeCell::new(t),
- }
- }
-}
-
-impl<T: ?Sized> RwLock<T> {
- /// Locks this rwlock with shared read access, blocking the current thread
- /// until it can be acquired.
- ///
- /// The calling thread will be blocked until there are no more writers which
- /// hold the lock. There may be other readers currently inside the lock when
- /// this method returns. This method does not provide any guarantees with
- /// respect to the ordering of whether contentious readers or writers will
- /// acquire the lock first.
- ///
- /// Returns an RAII guard which will release this thread's shared access
- /// once it is dropped.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock.
- /// The failure will occur immediately after the lock has been acquired.
- ///
- /// # Panics
- ///
- /// This function might panic when called if the lock is already held by the current thread.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::{Arc, RwLock};
- /// use std::thread;
- ///
- /// let lock = Arc::new(RwLock::new(1));
- /// let c_lock = lock.clone();
- ///
- /// let n = lock.read().unwrap();
- /// assert_eq!(*n, 1);
- ///
- /// thread::spawn(move || {
- /// let r = c_lock.read();
- /// assert!(r.is_ok());
- /// }).join().unwrap();
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
- unsafe {
- self.inner.read();
- RwLockReadGuard::new(self)
- }
- }
-
- /// Attempts to acquire this rwlock with shared read access.
- ///
- /// If the access could not be granted at this time, then `Err` is returned.
- /// Otherwise, an RAII guard is returned which will release the shared access
- /// when it is dropped.
- ///
- /// This function does not block.
- ///
- /// This function does not provide any guarantees with respect to the ordering
- /// of whether contentious readers or writers will acquire the lock first.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let lock = RwLock::new(1);
- ///
- /// match lock.try_read() {
- /// Ok(n) => assert_eq!(*n, 1),
- /// Err(_) => unreachable!(),
- /// };
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<T>> {
- unsafe {
- if self.inner.try_read() {
- Ok(RwLockReadGuard::new(self)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
- }
- }
-
- /// Locks this rwlock with exclusive write access, blocking the current
- /// thread until it can be acquired.
- ///
- /// This function will not return while other writers or other readers
- /// currently have access to the lock.
- ///
- /// Returns an RAII guard which will drop the write access of this rwlock
- /// when dropped.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock.
- /// An error will be returned when the lock is acquired.
- ///
- /// # Panics
- ///
- /// This function might panic when called if the lock is already held by the current thread.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let lock = RwLock::new(1);
- ///
- /// let mut n = lock.write().unwrap();
- /// *n = 2;
- ///
- /// assert!(lock.try_read().is_err());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
- unsafe {
- self.inner.write();
- RwLockWriteGuard::new(self)
- }
- }
-
- /// Attempts to lock this rwlock with exclusive write access.
- ///
- /// If the lock could not be acquired at this time, then `Err` is returned.
- /// Otherwise, an RAII guard is returned which will release the lock when
- /// it is dropped.
- ///
- /// This function does not block.
- ///
- /// This function does not provide any guarantees with respect to the ordering
- /// of whether contentious readers or writers will acquire the lock first.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let lock = RwLock::new(1);
- ///
- /// let n = lock.read().unwrap();
- /// assert_eq!(*n, 1);
- ///
- /// assert!(lock.try_write().is_err());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<T>> {
- unsafe {
- if self.inner.try_write() {
- Ok(RwLockWriteGuard::new(self)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
- }
- }
-
- /// Determines whether the lock is poisoned.
- ///
- /// If another thread is active, the lock can still become poisoned at any
- /// time. You should not trust a `false` value for program correctness
- /// without additional synchronization.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::{Arc, RwLock};
- /// use std::thread;
- ///
- /// let lock = Arc::new(RwLock::new(0));
- /// let c_lock = lock.clone();
- ///
- /// let _ = thread::spawn(move || {
- /// let _lock = c_lock.write().unwrap();
- /// panic!(); // the lock gets poisoned
- /// }).join();
- /// assert_eq!(lock.is_poisoned(), true);
- /// ```
- #[inline]
- #[stable(feature = "sync_poison", since = "1.2.0")]
- pub fn is_poisoned(&self) -> bool {
- self.poison.get()
- }
-
- /// Consumes this `RwLock`, returning the underlying data.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let lock = RwLock::new(String::new());
- /// {
- /// let mut s = lock.write().unwrap();
- /// *s = "modified".to_owned();
- /// }
- /// assert_eq!(lock.into_inner().unwrap(), "modified");
- /// ```
- #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
- pub fn into_inner(self) -> LockResult<T> where T: Sized {
- // We know statically that there are no outstanding references to
- // `self` so there's no need to lock the inner lock.
- //
- // To get the inner value, we'd like to call `data.into_inner()`,
- // but because `RwLock` impl-s `Drop`, we can't move out of it, so
- // we'll have to destructure it manually instead.
- unsafe {
- // Like `let RwLock { inner, poison, data } = self`.
- let (inner, poison, data) = {
- let RwLock { ref inner, ref poison, ref data } = self;
- (ptr::read(inner), ptr::read(poison), ptr::read(data))
- };
- mem::forget(self);
- inner.destroy(); // Keep in sync with the `Drop` impl.
- drop(inner);
-
- poison::map_result(poison.borrow(), |_| data.into_inner())
- }
- }
-
- /// Returns a mutable reference to the underlying data.
- ///
- /// Since this call borrows the `RwLock` mutably, no actual locking needs to
- /// take place---the mutable borrow statically guarantees no locks exist.
- ///
- /// # Errors
- ///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::sync::RwLock;
- ///
- /// let mut lock = RwLock::new(0);
- /// *lock.get_mut().unwrap() = 10;
- /// assert_eq!(*lock.read().unwrap(), 10);
- /// ```
- #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
- pub fn get_mut(&mut self) -> LockResult<&mut T> {
- // We know statically that there are no other references to `self`, so
- // there's no need to lock the inner lock.
- let data = unsafe { &mut *self.data.get() };
- poison::map_result(self.poison.borrow(), |_| data)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
- fn drop(&mut self) {
- // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
- unsafe { self.inner.destroy() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self.try_read() {
- Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
- Err(TryLockError::Poisoned(err)) => {
- f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish()
- },
- Err(TryLockError::WouldBlock) => {
- struct LockedPlaceholder;
- impl fmt::Debug for LockedPlaceholder {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
- }
-
- f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish()
- }
- }
- }
-}
-
-#[stable(feature = "rw_lock_default", since = "1.10.0")]
-impl<T: Default> Default for RwLock<T> {
- /// Creates a new `RwLock<T>`, with the `Default` value for T.
- fn default() -> RwLock<T> {
- RwLock::new(Default::default())
- }
-}
-
-#[stable(feature = "rw_lock_from", since = "1.24.0")]
-impl<T> From<T> for RwLock<T> {
- /// Creates a new instance of an `RwLock<T>` which is unlocked.
- /// This is equivalent to [`RwLock::new`].
- ///
- /// [`RwLock::new`]: #method.new
- fn from(t: T) -> Self {
- RwLock::new(t)
- }
-}
-
-impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
- unsafe fn new(lock: &'rwlock RwLock<T>)
- -> LockResult<RwLockReadGuard<'rwlock, T>> {
- poison::map_result(lock.poison.borrow(), |_| {
- RwLockReadGuard {
- __lock: lock,
- }
- })
- }
-}
-
-impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
- unsafe fn new(lock: &'rwlock RwLock<T>)
- -> LockResult<RwLockWriteGuard<'rwlock, T>> {
- poison::map_result(lock.poison.borrow(), |guard| {
- RwLockWriteGuard {
- __lock: lock,
- __poison: guard,
- }
- })
- }
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("RwLockReadGuard")
- .field("lock", &self.__lock)
- .finish()
- }
-}
-
-#[stable(feature = "std_guard_impls", since = "1.20.0")]
-impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'a, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- (**self).fmt(f)
- }
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("RwLockWriteGuard")
- .field("lock", &self.__lock)
- .finish()
- }
-}
-
-#[stable(feature = "std_guard_impls", since = "1.20.0")]
-impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'a, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- (**self).fmt(f)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> {
- fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.__lock.data.get() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> {
- fn drop(&mut self) {
- unsafe { self.__lock.inner.read_unlock(); }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> {
- fn drop(&mut self) {
- self.__lock.poison.done(&self.__poison);
- unsafe { self.__lock.inner.write_unlock(); }
- }
-}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
- use rand::{self, Rng};
- use sync::mpsc::channel;
- use thread;
- use sync::{Arc, RwLock, TryLockError};
- use sync::atomic::{AtomicUsize, Ordering};
-
- #[derive(Eq, PartialEq, Debug)]
- struct NonCopy(i32);
-
- #[test]
- fn smoke() {
- let l = RwLock::new(());
- drop(l.read().unwrap());
- drop(l.write().unwrap());
- drop((l.read().unwrap(), l.read().unwrap()));
- drop(l.write().unwrap());
- }
-
- #[test]
- fn frob() {
- const N: u32 = 10;
- const M: usize = 1000;
-
- let r = Arc::new(RwLock::new(()));
-
- let (tx, rx) = channel::<()>();
- for _ in 0..N {
- let tx = tx.clone();
- let r = r.clone();
- thread::spawn(move || {
- let mut rng = rand::thread_rng();
- for _ in 0..M {
- if rng.gen_weighted_bool(N) {
- drop(r.write().unwrap());
- } else {
- drop(r.read().unwrap());
- }
- }
- drop(tx);
- });
- }
- drop(tx);
- let _ = rx.recv();
- }
-
- #[test]
- fn test_rw_arc_poison_wr() {
- let arc = Arc::new(RwLock::new(1));
- let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move || {
- let _lock = arc2.write().unwrap();
- panic!();
- }).join();
- assert!(arc.read().is_err());
- }
-
- #[test]
- fn test_rw_arc_poison_ww() {
- let arc = Arc::new(RwLock::new(1));
- assert!(!arc.is_poisoned());
- let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move || {
- let _lock = arc2.write().unwrap();
- panic!();
- }).join();
- assert!(arc.write().is_err());
- assert!(arc.is_poisoned());
- }
-
- #[test]
- fn test_rw_arc_no_poison_rr() {
- let arc = Arc::new(RwLock::new(1));
- let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move || {
- let _lock = arc2.read().unwrap();
- panic!();
- }).join();
- let lock = arc.read().unwrap();
- assert_eq!(*lock, 1);
- }
- #[test]
- fn test_rw_arc_no_poison_rw() {
- let arc = Arc::new(RwLock::new(1));
- let arc2 = arc.clone();
- let _: Result<(), _> = thread::spawn(move || {
- let _lock = arc2.read().unwrap();
- panic!()
- }).join();
- let lock = arc.write().unwrap();
- assert_eq!(*lock, 1);
- }
-
- #[test]
- fn test_rw_arc() {
- let arc = Arc::new(RwLock::new(0));
- let arc2 = arc.clone();
- let (tx, rx) = channel();
-
- thread::spawn(move || {
- let mut lock = arc2.write().unwrap();
- for _ in 0..10 {
- let tmp = *lock;
- *lock = -1;
- thread::yield_now();
- *lock = tmp + 1;
- }
- tx.send(()).unwrap();
- });
-
- // Readers try to catch the writer in the act
- let mut children = Vec::new();
- for _ in 0..5 {
- let arc3 = arc.clone();
- children.push(thread::spawn(move || {
- let lock = arc3.read().unwrap();
- assert!(*lock >= 0);
- }));
- }
-
- // Wait for children to pass their asserts
- for r in children {
- assert!(r.join().is_ok());
- }
-
- // Wait for writer to finish
- rx.recv().unwrap();
- let lock = arc.read().unwrap();
- assert_eq!(*lock, 10);
- }
-
- #[test]
- fn test_rw_arc_access_in_unwind() {
- let arc = Arc::new(RwLock::new(1));
- let arc2 = arc.clone();
- let _ = thread::spawn(move || -> () {
- struct Unwinder {
- i: Arc<RwLock<isize>>,
- }
- impl Drop for Unwinder {
- fn drop(&mut self) {
- let mut lock = self.i.write().unwrap();
- *lock += 1;
- }
- }
- let _u = Unwinder { i: arc2 };
- panic!();
- }).join();
- let lock = arc.read().unwrap();
- assert_eq!(*lock, 2);
- }
-
- #[test]
- fn test_rwlock_unsized() {
- let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
- {
- let b = &mut *rw.write().unwrap();
- b[0] = 4;
- b[2] = 5;
- }
- let comp: &[i32] = &[4, 2, 5];
- assert_eq!(&*rw.read().unwrap(), comp);
- }
-
- #[test]
- fn test_rwlock_try_write() {
- let lock = RwLock::new(0isize);
- let read_guard = lock.read().unwrap();
-
- let write_result = lock.try_write();
- match write_result {
- Err(TryLockError::WouldBlock) => (),
- Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
- Err(_) => assert!(false, "unexpected error"),
- }
-
- drop(read_guard);
- }
-
- #[test]
- fn test_into_inner() {
- let m = RwLock::new(NonCopy(10));
- assert_eq!(m.into_inner().unwrap(), NonCopy(10));
- }
-
- #[test]
- fn test_into_inner_drop() {
- struct Foo(Arc<AtomicUsize>);
- impl Drop for Foo {
- fn drop(&mut self) {
- self.0.fetch_add(1, Ordering::SeqCst);
- }
- }
- let num_drops = Arc::new(AtomicUsize::new(0));
- let m = RwLock::new(Foo(num_drops.clone()));
- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
- {
- let _inner = m.into_inner().unwrap();
- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
- }
- assert_eq!(num_drops.load(Ordering::SeqCst), 1);
- }
-
- #[test]
- fn test_into_inner_poison() {
- let m = Arc::new(RwLock::new(NonCopy(10)));
- let m2 = m.clone();
- let _ = thread::spawn(move || {
- let _lock = m2.write().unwrap();
- panic!("test panic in inner thread to poison RwLock");
- }).join();
-
- assert!(m.is_poisoned());
- match Arc::try_unwrap(m).unwrap().into_inner() {
- Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
- }
- }
-
- #[test]
- fn test_get_mut() {
- let mut m = RwLock::new(NonCopy(10));
- *m.get_mut().unwrap() = NonCopy(20);
- assert_eq!(m.into_inner().unwrap(), NonCopy(20));
- }
-
- #[test]
- fn test_get_mut_poison() {
- let m = Arc::new(RwLock::new(NonCopy(10)));
- let m2 = m.clone();
- let _ = thread::spawn(move || {
- let _lock = m2.write().unwrap();
- panic!("test panic in inner thread to poison RwLock");
- }).join();
-
- assert!(m.is_poisoned());
- match Arc::try_unwrap(m).unwrap().get_mut() {
- Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
- Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
- }
- }
-}