From 96c3a13680d521387007e2f6575483c24561ecb3 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Fri, 23 Jan 2015 11:47:04 -0800 Subject: [PATCH 1/2] sync: Add is_poisoned to Mutex and RwLock --- src/libstd/sync/mutex.rs | 13 +++++++++++++ src/libstd/sync/rwlock.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 7531d5b058d79..74692c1273c27 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -228,6 +228,17 @@ impl Mutex { Err(TryLockError::WouldBlock) } } + + /// Determine 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. + #[inline] + #[unstable(feature = "std_misc")] + pub fn is_poisoned(&self) -> bool { + self.inner.poison.get() + } } #[unsafe_destructor] @@ -458,12 +469,14 @@ mod test { #[test] fn test_mutex_arc_poison() { let arc = Arc::new(Mutex::new(1)); + assert!(!arc.is_poisoned()); let arc2 = arc.clone(); let _ = Thread::scoped(move|| { let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); }).join(); assert!(arc.lock().is_err()); + assert!(arc.is_poisoned()); } #[test] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 6efbcf894156e..c4f1f2ccadddd 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -237,6 +237,17 @@ impl RwLock { Err(TryLockError::WouldBlock) } } + + /// Determine 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. + #[inline] + #[unstable(feature = "std_misc")] + pub fn is_poisoned(&self) -> bool { + self.inner.poison.get() + } } #[unsafe_destructor] @@ -451,12 +462,14 @@ mod tests { #[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::scoped(move|| { let _lock = arc2.write().unwrap(); panic!(); }).join(); assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); } #[test] From 7324c2cf4f09d44d1bde8c37716de9eca4aac565 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Fri, 23 Jan 2015 11:58:49 -0800 Subject: [PATCH 2/2] sync: Expose PoisonError::new --- src/libstd/sync/condvar.rs | 12 ++++++------ src/libstd/sync/poison.rs | 14 ++++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 2ae81ad7dffe2..d4d722cab3d92 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -16,7 +16,7 @@ use sys::time::SteadyTime; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use time::Duration; -use sync::{mutex, MutexGuard}; +use sync::{mutex, MutexGuard, PoisonError}; /// A Condition Variable /// @@ -228,7 +228,7 @@ impl StaticCondvar { mutex::guard_poison(&guard).get() }; if poisoned { - Err(poison::new_poison_error(guard)) + Err(PoisonError::new(guard)) } else { Ok(guard) } @@ -249,7 +249,7 @@ impl StaticCondvar { (mutex::guard_poison(&guard).get(), success) }; if poisoned { - Err(poison::new_poison_error((guard, success))) + Err(PoisonError::new((guard, success))) } else { Ok((guard, success)) } @@ -276,7 +276,7 @@ impl StaticCondvar { while !f(guard_result .as_mut() .map(|g| &mut **g) - .map_err(|e| poison::new_poison_error(&mut **e.get_mut()))) { + .map_err(|e| PoisonError::new(&mut **e.get_mut()))) { let now = SteadyTime::now(); let consumed = &now - &start; let guard = guard_result.unwrap_or_else(|e| e.into_inner()); @@ -284,7 +284,7 @@ impl StaticCondvar { Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout), Err(err) => { let (new_guard, no_timeout) = err.into_inner(); - (Err(poison::new_poison_error(new_guard)), no_timeout) + (Err(PoisonError::new(new_guard)), no_timeout) } }; guard_result = new_guard_result; @@ -292,7 +292,7 @@ impl StaticCondvar { let result = f(guard_result .as_mut() .map(|g| &mut **g) - .map_err(|e| poison::new_poison_error(&mut **e.get_mut()))); + .map_err(|e| PoisonError::new(&mut **e.get_mut()))); return poison::map_result(guard_result, |g| (g, result)); } } diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index d9bc37d312e86..a93bd31f5ae38 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -23,7 +23,7 @@ impl Flag { pub fn borrow(&self) -> LockResult { let ret = Guard { panicking: Thread::panicking() }; if unsafe { *self.failed.get() } { - Err(new_poison_error(ret)) + Err(PoisonError::new(ret)) } else { Ok(ret) } @@ -110,6 +110,12 @@ impl Error for PoisonError { } impl PoisonError { + /// Create a `PoisonError`. + #[unstable(feature = "std_misc")] + pub fn new(guard: T) -> PoisonError { + PoisonError { guard: guard } + } + /// Consumes this error indicating that a lock is poisoned, returning the /// underlying guard to allow access regardless. #[unstable(feature = "std_misc")] @@ -171,15 +177,11 @@ impl Error for TryLockError { } } -pub fn new_poison_error(guard: T) -> PoisonError { - PoisonError { guard: guard } -} - pub fn map_result(result: LockResult, f: F) -> LockResult where F: FnOnce(T) -> U { match result { Ok(t) => Ok(f(t)), - Err(PoisonError { guard }) => Err(new_poison_error(f(guard))) + Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))) } }