From a4343e99c0e38bcb31386d48a6682e3a1896a0cc Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Mon, 11 Jan 2016 19:10:02 -0800 Subject: [PATCH 1/3] Add guard map methods for transforming guards to contain sub-borrows. This is very useful when the lock is synchronizing access to a data structure and you would like to return or store guards which contain references to data inside the data structure instead of the data structure itself. --- src/libstd/sync/mutex.rs | 54 ++++++++++++++++++++++- src/libstd/sync/rwlock.rs | 90 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 6b20e51967d88..bdf8ca146fa74 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -379,6 +379,43 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { } }) } + + /// Transform this guard to hold a sub-borrow of the original data. + /// + /// Applies the supplied closure to the data, returning a new lock + /// guard referencing the borrow returned by the closure. + /// + /// ```rust + /// # use std::sync::{Mutex, MutexGuard}; + /// let x = Mutex::new(vec![1, 2]); + /// + /// { + /// let y = MutexGuard::map(x.lock().unwrap(), |v| &mut v[0]); + /// *y = 3; + /// } + /// + /// assert_eq!(&*x.lock(), &[3, 2]); + /// ``` + #[unstable(feature = "guard_map", + reason = "recently added, needs RFC for stabilization", + issue = "0")] + pub fn map(this: Self, cb: F) -> MutexGuard<'mutex, U> + where F: FnOnce(&'mutex mut T) -> &'mutex mut U { + let new_data = unsafe { + let data = cb(&mut *this.__data.get()); + mem::transmute::<&'mutex mut U, &'mutex UnsafeCell>(data) + }; + + let lock = unsafe { ptr::read(&this.__lock) }; + let poison = unsafe { ptr::read(&this.__poison) }; + mem::forget(this); + + MutexGuard { + __lock: lock, + __data: new_data, + __poison: poison + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -421,7 +458,7 @@ mod tests { use prelude::v1::*; use sync::mpsc::channel; - use sync::{Arc, Mutex, StaticMutex, Condvar}; + use sync::{Arc, Mutex, StaticMutex, Condvar, MutexGuard}; use sync::atomic::{AtomicUsize, Ordering}; use thread; @@ -665,4 +702,19 @@ mod tests { let comp: &[i32] = &[4, 2, 5]; assert_eq!(&*mutex.lock().unwrap(), comp); } + + #[test] + fn test_mutex_guard_map_panic() { + let mutex = Arc::new(Mutex::new(vec![1, 2])); + let mutex2 = mutex.clone(); + + thread::spawn(move || { + let _ = MutexGuard::map::(mutex2.lock().unwrap(), |_| panic!()); + }).join().unwrap_err(); + + match mutex.lock() { + Ok(r) => panic!("Lock on poisioned Mutex is Ok: {:?}", &*r), + Err(_) => {} + }; + } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 3dbef43548136..04f00ed42d050 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -121,7 +121,7 @@ pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new(); #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, - __data: &'a UnsafeCell, + __data: &'a T, } #[stable(feature = "rust1", since = "1.0.0")] @@ -417,10 +417,37 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { poison::map_result(lock.poison.borrow(), |_| { RwLockReadGuard { __lock: lock, - __data: data, + __data: unsafe { &*data.get() }, } }) } + + /// Transform this guard to hold a sub-borrow of the original data. + /// + /// Applies the supplied closure to the data, returning a new lock + /// guard referencing the borrow returned by the closure. + /// + /// ```rust + /// # use std::sync::{RwLockReadGuard, RwLock}; + /// let x = RwLock::new(vec![1, 2]); + /// + /// let y = RwLockReadGuard::map(x.read().unwrap(), |v| &v[0]); + /// assert_eq!(*y, 1); + /// ``` + #[unstable(feature = "guard_map", + reason = "recently added, needs RFC for stabilization", + issue = "0")] + pub fn map(this: Self, cb: F) -> RwLockReadGuard<'rwlock, U> + where F: FnOnce(&'rwlock T) -> &'rwlock U { + let new = RwLockReadGuard { + __lock: this.__lock, + __data: cb(this.__data) + }; + + mem::forget(this); + + new + } } impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { @@ -434,13 +461,52 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { } }) } + + /// Transform this guard to hold a sub-borrow of the original data. + /// + /// Applies the supplied closure to the data, returning a new lock + /// guard referencing the borrow returned by the closure. + /// + /// ```rust + /// # use std::sync::{RwLockWriteGuard, RwLock}; + /// let x = RwLock::new(vec![1, 2]); + /// + /// { + /// let y = RwLockWriteGuard::map(x.write().unwrap(), |v| &mut v[0]); + /// assert_eq!(*y, 1); + /// + /// *y = 10; + /// } + /// + /// assert_eq!(&**x.read().unwrap(), &[10, 2]); + /// ``` + #[unstable(feature = "guard_map", + reason = "recently added, needs RFC for stabilization", + issue = "0")] + pub fn map(this: Self, cb: F) -> RwLockWriteGuard<'rwlock, U> + where F: FnOnce(&'rwlock mut T) -> &'rwlock mut U { + let new_data = unsafe { + let data: &'rwlock mut T = &mut *this.__data.get(); + mem::transmute::<&'rwlock mut U, &'rwlock UnsafeCell>(cb(data)) + }; + + let poison = unsafe { ptr::read(&this.__poison) }; + let lock = unsafe { ptr::read(&this.__lock) }; + mem::forget(this); + + RwLockWriteGuard { + __lock: lock, + __data: new_data, + __poison: poison + } + } } #[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.__data.get() } } + fn deref(&self) -> &T { self.__data } } #[stable(feature = "rust1", since = "1.0.0")] @@ -481,7 +547,7 @@ mod tests { use rand::{self, Rng}; use sync::mpsc::channel; use thread; - use sync::{Arc, RwLock, StaticRwLock, TryLockError}; + use sync::{Arc, RwLock, StaticRwLock, TryLockError, RwLockWriteGuard}; use sync::atomic::{AtomicUsize, Ordering}; #[derive(Eq, PartialEq, Debug)] @@ -729,4 +795,20 @@ mod tests { Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), } } + + #[test] + fn test_rwlock_write_map_poison() { + let rwlock = Arc::new(RwLock::new(vec![1, 2])); + let rwlock2 = rwlock.clone(); + + thread::spawn(move || { + let _ = RwLockWriteGuard::map::(rwlock2.write().unwrap(), |_| panic!()); + }).join().unwrap_err(); + + match rwlock.read() { + Ok(r) => panic!("Read lock on poisioned RwLock is Ok: {:?}", &*r), + Err(_) => {} + }; + } } + From bf60078b48649ef4d3a9cb0034208672b82e9b51 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Fri, 29 Jan 2016 23:36:38 -0800 Subject: [PATCH 2/3] Change MutexGuard and RwLockWriteGuard to store &mut T not &UnsafeCell This centralizes the unsafety of converting from UnsafeCell to &mut T. --- src/libstd/sync/mutex.rs | 37 +++++++++++++++--------------- src/libstd/sync/rwlock.rs | 47 ++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index bdf8ca146fa74..ab566f3f94583 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -172,7 +172,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). __lock: &'a StaticMutex, - __data: &'a UnsafeCell, + __data: &'a mut T, __poison: poison::Guard, } @@ -212,7 +212,7 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { unsafe { self.inner.lock.lock() } - MutexGuard::new(&*self.inner, &self.data) + unsafe { MutexGuard::new(&*self.inner, &self.data) } } /// Attempts to acquire this lock. @@ -231,7 +231,7 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_lock(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_lock() } { - Ok(try!(MutexGuard::new(&*self.inner, &self.data))) + Ok(try!(unsafe { MutexGuard::new(&*self.inner, &self.data) })) } else { Err(TryLockError::WouldBlock) } @@ -339,14 +339,14 @@ impl StaticMutex { #[inline] pub fn lock(&'static self) -> LockResult> { unsafe { self.lock.lock() } - MutexGuard::new(self, &DUMMY.0) + unsafe { MutexGuard::new(self, &DUMMY.0) } } /// Attempts to grab this lock, see `Mutex::try_lock` #[inline] pub fn try_lock(&'static self) -> TryLockResult> { if unsafe { self.lock.try_lock() } { - Ok(try!(MutexGuard::new(self, &DUMMY.0))) + Ok(try!(unsafe { MutexGuard::new(self, &DUMMY.0) })) } else { Err(TryLockError::WouldBlock) } @@ -369,12 +369,12 @@ impl StaticMutex { impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { - fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) + unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { MutexGuard { __lock: lock, - __data: data, + __data: &mut *data.get(), __poison: guard, } }) @@ -385,7 +385,10 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { /// Applies the supplied closure to the data, returning a new lock /// guard referencing the borrow returned by the closure. /// + /// # Examples + /// /// ```rust + /// # #![feature(guard_map)] /// # use std::sync::{Mutex, MutexGuard}; /// let x = Mutex::new(vec![1, 2]); /// @@ -401,13 +404,15 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { issue = "0")] pub fn map(this: Self, cb: F) -> MutexGuard<'mutex, U> where F: FnOnce(&'mutex mut T) -> &'mutex mut U { - let new_data = unsafe { - let data = cb(&mut *this.__data.get()); - mem::transmute::<&'mutex mut U, &'mutex UnsafeCell>(data) - }; + // Compute the new data while still owning the original lock + // in order to correctly poison if the callback panics. + let data = unsafe { ptr::read(&this.__data) }; + let new_data = cb(data); - let lock = unsafe { ptr::read(&this.__lock) }; + // We don't want to unlock the lock by running the destructor of the + // original lock, so just read the fields we need and forget it. let poison = unsafe { ptr::read(&this.__poison) }; + let lock = unsafe { ptr::read(&this.__lock) }; mem::forget(this); MutexGuard { @@ -422,16 +427,12 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.__data.get() } - } + fn deref(&self) -> &T {self.__data } } #[stable(feature = "rust1", since = "1.0.0")] impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__data.get() } - } + fn deref_mut(&mut self) -> &mut T { self.__data } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 04f00ed42d050..7c1fcd6dea7c7 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -133,7 +133,7 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, - __data: &'a UnsafeCell, + __data: &'a mut T, __poison: poison::Guard, } @@ -178,7 +178,7 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&self) -> LockResult> { unsafe { self.inner.lock.read() } - RwLockReadGuard::new(&*self.inner, &self.data) + unsafe { RwLockReadGuard::new(&*self.inner, &self.data) } } /// Attempts to acquire this rwlock with shared read access. @@ -202,7 +202,7 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_read(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_read() } { - Ok(try!(RwLockReadGuard::new(&*self.inner, &self.data))) + Ok(try!(unsafe { RwLockReadGuard::new(&*self.inner, &self.data) })) } else { Err(TryLockError::WouldBlock) } @@ -226,7 +226,7 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&self) -> LockResult> { unsafe { self.inner.lock.write() } - RwLockWriteGuard::new(&*self.inner, &self.data) + unsafe { RwLockWriteGuard::new(&*self.inner, &self.data) } } /// Attempts to lock this rwlock with exclusive write access. @@ -250,7 +250,7 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_write(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_write() } { - Ok(try!(RwLockWriteGuard::new(&*self.inner, &self.data))) + Ok(try!(unsafe { RwLockWriteGuard::new(&*self.inner, &self.data) })) } else { Err(TryLockError::WouldBlock) } @@ -361,7 +361,7 @@ impl StaticRwLock { #[inline] pub fn read(&'static self) -> LockResult> { unsafe { self.lock.read() } - RwLockReadGuard::new(self, &DUMMY.0) + unsafe { RwLockReadGuard::new(self, &DUMMY.0) } } /// Attempts to acquire this lock with shared read access. @@ -371,7 +371,7 @@ impl StaticRwLock { pub fn try_read(&'static self) -> TryLockResult> { if unsafe { self.lock.try_read() } { - Ok(try!(RwLockReadGuard::new(self, &DUMMY.0))) + unsafe { Ok(try!(RwLockReadGuard::new(self, &DUMMY.0))) } } else { Err(TryLockError::WouldBlock) } @@ -384,7 +384,7 @@ impl StaticRwLock { #[inline] pub fn write(&'static self) -> LockResult> { unsafe { self.lock.write() } - RwLockWriteGuard::new(self, &DUMMY.0) + unsafe { RwLockWriteGuard::new(self, &DUMMY.0) } } /// Attempts to lock this rwlock with exclusive write access. @@ -394,7 +394,7 @@ impl StaticRwLock { pub fn try_write(&'static self) -> TryLockResult> { if unsafe { self.lock.try_write() } { - Ok(try!(RwLockWriteGuard::new(self, &DUMMY.0))) + Ok(unsafe { try!(RwLockWriteGuard::new(self, &DUMMY.0)) }) } else { Err(TryLockError::WouldBlock) } @@ -412,12 +412,12 @@ impl StaticRwLock { } impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { - fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) + unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |_| { RwLockReadGuard { __lock: lock, - __data: unsafe { &*data.get() }, + __data: &*data.get(), } }) } @@ -427,7 +427,10 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { /// Applies the supplied closure to the data, returning a new lock /// guard referencing the borrow returned by the closure. /// + /// # Examples + /// /// ```rust + /// # #![feature(guard_map)] /// # use std::sync::{RwLockReadGuard, RwLock}; /// let x = RwLock::new(vec![1, 2]); /// @@ -451,12 +454,12 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { } impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) + unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { RwLockWriteGuard { __lock: lock, - __data: data, + __data: &mut *data.get(), __poison: guard, } }) @@ -467,7 +470,10 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { /// Applies the supplied closure to the data, returning a new lock /// guard referencing the borrow returned by the closure. /// + /// # Examples + /// /// ```rust + /// # #![feature(guard_map)] /// # use std::sync::{RwLockWriteGuard, RwLock}; /// let x = RwLock::new(vec![1, 2]); /// @@ -485,11 +491,13 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { issue = "0")] pub fn map(this: Self, cb: F) -> RwLockWriteGuard<'rwlock, U> where F: FnOnce(&'rwlock mut T) -> &'rwlock mut U { - let new_data = unsafe { - let data: &'rwlock mut T = &mut *this.__data.get(); - mem::transmute::<&'rwlock mut U, &'rwlock UnsafeCell>(cb(data)) - }; + // Compute the new data while still owning the original lock + // in order to correctly poison if the callback panics. + let data = unsafe { ptr::read(&this.__data) }; + let new_data = cb(data); + // We don't want to unlock the lock by running the destructor of the + // original lock, so just read the fields we need and forget it. let poison = unsafe { ptr::read(&this.__poison) }; let lock = unsafe { ptr::read(&this.__lock) }; mem::forget(this); @@ -513,13 +521,12 @@ impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { type Target = T; - fn deref(&self) -> &T { unsafe { &*self.__data.get() } } + fn deref(&self) -> &T { self.__data } } #[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.__data.get() } + fn deref_mut(&mut self) -> &mut T { self.__data } } From fc875b087cdd844fa61204db30c287f3c3179d92 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Sat, 30 Jan 2016 16:39:03 -0800 Subject: [PATCH 3/3] Add issue number to guard map methods. --- src/libstd/sync/mutex.rs | 46 +++++++++++++--------- src/libstd/sync/rwlock.rs | 81 ++++++++++++++++++++++++--------------- 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index ab566f3f94583..a6ab54730762d 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -211,8 +211,10 @@ impl Mutex { /// this call will return an error once the mutex is acquired. #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { - unsafe { self.inner.lock.lock() } - unsafe { MutexGuard::new(&*self.inner, &self.data) } + unsafe { + self.inner.lock.lock(); + MutexGuard::new(&*self.inner, &self.data) + } } /// Attempts to acquire this lock. @@ -230,10 +232,12 @@ impl Mutex { /// acquired. #[stable(feature = "rust1", since = "1.0.0")] pub fn try_lock(&self) -> TryLockResult> { - if unsafe { self.inner.lock.try_lock() } { - Ok(try!(unsafe { MutexGuard::new(&*self.inner, &self.data) })) - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.inner.lock.try_lock() { + Ok(try!(MutexGuard::new(&*self.inner, &self.data))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -338,17 +342,21 @@ impl StaticMutex { /// Acquires this lock, see `Mutex::lock` #[inline] pub fn lock(&'static self) -> LockResult> { - unsafe { self.lock.lock() } - unsafe { MutexGuard::new(self, &DUMMY.0) } + unsafe { + self.lock.lock(); + MutexGuard::new(self, &DUMMY.0) + } } /// Attempts to grab this lock, see `Mutex::try_lock` #[inline] pub fn try_lock(&'static self) -> TryLockResult> { - if unsafe { self.lock.try_lock() } { - Ok(try!(unsafe { MutexGuard::new(self, &DUMMY.0) })) - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.lock.try_lock() { + Ok(try!(MutexGuard::new(self, &DUMMY.0))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -393,17 +401,18 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { /// let x = Mutex::new(vec![1, 2]); /// /// { - /// let y = MutexGuard::map(x.lock().unwrap(), |v| &mut v[0]); + /// let mut y = MutexGuard::map(x.lock().unwrap(), |v| &mut v[0]); /// *y = 3; /// } /// - /// assert_eq!(&*x.lock(), &[3, 2]); + /// assert_eq!(&*x.lock().unwrap(), &[3, 2]); /// ``` #[unstable(feature = "guard_map", reason = "recently added, needs RFC for stabilization", - issue = "0")] + issue = "27746")] pub fn map(this: Self, cb: F) -> MutexGuard<'mutex, U> - where F: FnOnce(&'mutex mut T) -> &'mutex mut U { + where F: FnOnce(&'mutex mut T) -> &'mutex mut U + { // Compute the new data while still owning the original lock // in order to correctly poison if the callback panics. let data = unsafe { ptr::read(&this.__data) }; @@ -411,8 +420,9 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { // We don't want to unlock the lock by running the destructor of the // original lock, so just read the fields we need and forget it. - let poison = unsafe { ptr::read(&this.__poison) }; - let lock = unsafe { ptr::read(&this.__lock) }; + let (poison, lock) = unsafe { + (ptr::read(&this.__poison), ptr::read(&this.__lock)) + }; mem::forget(this); MutexGuard { diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 7c1fcd6dea7c7..2b3233b2dabef 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -177,8 +177,10 @@ impl RwLock { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&self) -> LockResult> { - unsafe { self.inner.lock.read() } - unsafe { RwLockReadGuard::new(&*self.inner, &self.data) } + unsafe { + self.inner.lock.read(); + RwLockReadGuard::new(&*self.inner, &self.data) + } } /// Attempts to acquire this rwlock with shared read access. @@ -201,10 +203,12 @@ impl RwLock { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn try_read(&self) -> TryLockResult> { - if unsafe { self.inner.lock.try_read() } { - Ok(try!(unsafe { RwLockReadGuard::new(&*self.inner, &self.data) })) - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.inner.lock.try_read() { + Ok(try!(RwLockReadGuard::new(&*self.inner, &self.data))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -225,8 +229,10 @@ impl RwLock { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&self) -> LockResult> { - unsafe { self.inner.lock.write() } - unsafe { RwLockWriteGuard::new(&*self.inner, &self.data) } + unsafe { + self.inner.lock.write(); + RwLockWriteGuard::new(&*self.inner, &self.data) + } } /// Attempts to lock this rwlock with exclusive write access. @@ -249,10 +255,12 @@ impl RwLock { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn try_write(&self) -> TryLockResult> { - if unsafe { self.inner.lock.try_write() } { - Ok(try!(unsafe { RwLockWriteGuard::new(&*self.inner, &self.data) })) - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.inner.lock.try_write() { + Ok(try!(RwLockWriteGuard::new(&*self.inner, &self.data))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -360,8 +368,10 @@ impl StaticRwLock { /// See `RwLock::read`. #[inline] pub fn read(&'static self) -> LockResult> { - unsafe { self.lock.read() } - unsafe { RwLockReadGuard::new(self, &DUMMY.0) } + unsafe { + self.lock.read(); + RwLockReadGuard::new(self, &DUMMY.0) + } } /// Attempts to acquire this lock with shared read access. @@ -370,10 +380,12 @@ impl StaticRwLock { #[inline] pub fn try_read(&'static self) -> TryLockResult> { - if unsafe { self.lock.try_read() } { - unsafe { Ok(try!(RwLockReadGuard::new(self, &DUMMY.0))) } - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.lock.try_read(){ + Ok(try!(RwLockReadGuard::new(self, &DUMMY.0))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -383,8 +395,10 @@ impl StaticRwLock { /// See `RwLock::write`. #[inline] pub fn write(&'static self) -> LockResult> { - unsafe { self.lock.write() } - unsafe { RwLockWriteGuard::new(self, &DUMMY.0) } + unsafe { + self.lock.write(); + RwLockWriteGuard::new(self, &DUMMY.0) + } } /// Attempts to lock this rwlock with exclusive write access. @@ -393,10 +407,12 @@ impl StaticRwLock { #[inline] pub fn try_write(&'static self) -> TryLockResult> { - if unsafe { self.lock.try_write() } { - Ok(unsafe { try!(RwLockWriteGuard::new(self, &DUMMY.0)) }) - } else { - Err(TryLockError::WouldBlock) + unsafe { + if self.lock.try_write() { + Ok(try!(RwLockWriteGuard::new(self, &DUMMY.0))) + } else { + Err(TryLockError::WouldBlock) + } } } @@ -439,9 +455,10 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { /// ``` #[unstable(feature = "guard_map", reason = "recently added, needs RFC for stabilization", - issue = "0")] + issue = "27746")] pub fn map(this: Self, cb: F) -> RwLockReadGuard<'rwlock, U> - where F: FnOnce(&'rwlock T) -> &'rwlock U { + where F: FnOnce(&'rwlock T) -> &'rwlock U + { let new = RwLockReadGuard { __lock: this.__lock, __data: cb(this.__data) @@ -478,7 +495,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { /// let x = RwLock::new(vec![1, 2]); /// /// { - /// let y = RwLockWriteGuard::map(x.write().unwrap(), |v| &mut v[0]); + /// let mut y = RwLockWriteGuard::map(x.write().unwrap(), |v| &mut v[0]); /// assert_eq!(*y, 1); /// /// *y = 10; @@ -488,9 +505,10 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { /// ``` #[unstable(feature = "guard_map", reason = "recently added, needs RFC for stabilization", - issue = "0")] + issue = "27746")] pub fn map(this: Self, cb: F) -> RwLockWriteGuard<'rwlock, U> - where F: FnOnce(&'rwlock mut T) -> &'rwlock mut U { + where F: FnOnce(&'rwlock mut T) -> &'rwlock mut U + { // Compute the new data while still owning the original lock // in order to correctly poison if the callback panics. let data = unsafe { ptr::read(&this.__data) }; @@ -498,8 +516,9 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { // We don't want to unlock the lock by running the destructor of the // original lock, so just read the fields we need and forget it. - let poison = unsafe { ptr::read(&this.__poison) }; - let lock = unsafe { ptr::read(&this.__lock) }; + let (poison, lock) = unsafe { + (ptr::read(&this.__poison), ptr::read(&this.__lock)) + }; mem::forget(this); RwLockWriteGuard {