about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-02-08 08:21:44 +0000
committerbors <bors@rust-lang.org>2015-02-08 08:21:44 +0000
commitd4f9ec566249f88845c88c8b897097a262b4e0af (patch)
tree0b19bfaf039394010d7d95783b572cd1dfbe76ec
parentcdaf3a4393927ddfba071cfbfe86d95b68e7ae3e (diff)
parent7324c2cf4f09d44d1bde8c37716de9eca4aac565 (diff)
downloadrust-d4f9ec566249f88845c88c8b897097a262b4e0af.tar.gz
rust-d4f9ec566249f88845c88c8b897097a262b4e0af.zip
Auto merge of #21565 - kmcallister:poison, r=alexcrichton
I needed these to implement efficient poisoning in [seqloq](https://github.com/kmcallister/seqloq/tree/poison).
-rw-r--r--src/libstd/sync/condvar.rs12
-rw-r--r--src/libstd/sync/mutex.rs13
-rw-r--r--src/libstd/sync/poison.rs14
-rw-r--r--src/libstd/sync/rwlock.rs13
4 files changed, 40 insertions, 12 deletions
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 2ae81ad7dff..d4d722cab3d 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/mutex.rs b/src/libstd/sync/mutex.rs
index 7531d5b058d..74692c1273c 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -228,6 +228,17 @@ impl<T: Send> Mutex<T> {
             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/poison.rs b/src/libstd/sync/poison.rs
index d9bc37d312e..a93bd31f5ae 100644
--- a/src/libstd/sync/poison.rs
+++ b/src/libstd/sync/poison.rs
@@ -23,7 +23,7 @@ impl Flag {
     pub fn borrow(&self) -> LockResult<Guard> {
         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<T> Error for PoisonError<T> {
 }
 
 impl<T> PoisonError<T> {
+    /// Create a `PoisonError`.
+    #[unstable(feature = "std_misc")]
+    pub fn new(guard: T) -> PoisonError<T> {
+        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<T> Error for TryLockError<T> {
     }
 }
 
-pub fn new_poison_error<T>(guard: T) -> PoisonError<T> {
-    PoisonError { guard: guard }
-}
-
 pub fn map_result<T, U, F>(result: LockResult<T>, f: F)
                            -> LockResult<U>
                            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)))
     }
 }
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 6efbcf89415..c4f1f2ccadd 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -237,6 +237,17 @@ impl<T: Send + Sync> RwLock<T> {
             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<uint, _> = Thread::scoped(move|| {
             let _lock = arc2.write().unwrap();
             panic!();
         }).join();
         assert!(arc.write().is_err());
+        assert!(arc.is_poisoned());
     }
 
     #[test]