From 10a400ffaa8b67add66a62bde0ef3c415d7aed5f Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Tue, 2 Jul 2013 13:37:19 -0400 Subject: Reimplement ARC::unwrap() and friends. --- src/libextra/arc.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 8 deletions(-) (limited to 'src/libextra') diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 054b4ce5177..404d5bfde58 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -50,9 +50,9 @@ use std::borrow; /// As sync::condvar, a mechanism for unlock-and-descheduling and signaling. pub struct Condvar<'self> { - is_mutex: bool, - failed: &'self mut bool, - cond: &'self sync::Condvar<'self> + priv is_mutex: bool, + priv failed: &'self mut bool, + priv cond: &'self sync::Condvar<'self> } impl<'self> Condvar<'self> { @@ -108,7 +108,7 @@ impl<'self> Condvar<'self> { ****************************************************************************/ /// An atomically reference counted wrapper for shared immutable state. -pub struct ARC { x: UnsafeAtomicRcBox } +pub struct ARC { priv x: UnsafeAtomicRcBox } /// Create an atomically reference counted wrapper. pub fn ARC(data: T) -> ARC { @@ -123,6 +123,20 @@ impl ARC { pub fn get<'a>(&'a self) -> &'a T { unsafe { &*self.x.get_immut() } } + + /** + * Retrieve the data back out of the ARC. This function blocks until the + * reference given to it is the last existing one, and then unwrap the data + * instead of destroying it. + * + * If multiple tasks call unwrap, all but the first will fail. Do not call + * unwrap from a task that holds another reference to the same ARC; it is + * guaranteed to deadlock. + */ + pub fn unwrap(self) -> T { + let ARC { x: x } = self; + unsafe { x.unwrap() } + } } /** @@ -143,9 +157,9 @@ impl Clone for ARC { ****************************************************************************/ #[doc(hidden)] -struct MutexARCInner { lock: Mutex, failed: bool, data: T } +struct MutexARCInner { priv lock: Mutex, priv failed: bool, priv data: T } /// An ARC with mutable data protected by a blocking mutex. -struct MutexARC { x: UnsafeAtomicRcBox> } +struct MutexARC { priv x: UnsafeAtomicRcBox> } /// Create a mutex-protected ARC with the supplied data. pub fn MutexARC(user_data: T) -> MutexARC { @@ -225,6 +239,22 @@ impl MutexARC { cond: cond }) } } + + /** + * Retrieves the data, blocking until all other references are dropped, + * exactly as arc::unwrap. + * + * Will additionally fail if another task has failed while accessing the arc. + */ + pub fn unwrap(self) -> T { + let MutexARC { x: x } = self; + let inner = unsafe { x.unwrap() }; + let MutexARCInner { failed: failed, data: data, _ } = inner; + if failed { + fail!(~"Can't unwrap poisoned MutexARC - another task failed inside!"); + } + data + } } // Common code for {mutex.access,rwlock.write}{,_cond}. @@ -268,7 +298,7 @@ fn PoisonOnFail<'r>(failed: &'r mut bool) -> PoisonOnFail { ****************************************************************************/ #[doc(hidden)] -struct RWARCInner { lock: RWlock, failed: bool, data: T } +struct RWARCInner { priv lock: RWlock, priv failed: bool, priv data: T } /** * A dual-mode ARC protected by a reader-writer lock. The data can be accessed * mutably or immutably, and immutably-accessing tasks may run concurrently. @@ -278,7 +308,7 @@ struct RWARCInner { lock: RWlock, failed: bool, data: T } #[mutable] // XXX remove after snap #[no_freeze] struct RWARC { - x: UnsafeAtomicRcBox>, + priv x: UnsafeAtomicRcBox>, } /// Create a reader/writer ARC with the supplied data. @@ -429,6 +459,23 @@ impl RWARC { } } } + + /** + * Retrieves the data, blocking until all other references are dropped, + * exactly as arc::unwrap. + * + * Will additionally fail if another task has failed while accessing the arc + * in write mode. + */ + pub fn unwrap(self) -> T { + let RWARC { x: x, _ } = self; + let inner = unsafe { x.unwrap() }; + let RWARCInner { failed: failed, data: data, _ } = inner; + if failed { + fail!(~"Can't unwrap poisoned RWARC - another task failed inside!") + } + data + } } // Borrowck rightly complains about immutably aliasing the rwlock in order to @@ -611,6 +658,23 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] + pub fn test_mutex_arc_unwrap_poison() { + let arc = MutexARC(1); + let arc2 = ~(&arc).clone(); + let (p, c) = comm::stream(); + do task::spawn { + unsafe { + do arc2.access |one| { + c.send(()); + assert!(*one == 2); + } + } + } + let _ = p.recv(); + let one = arc.unwrap(); + assert!(one == 1); + } + #[test] #[should_fail] #[ignore(cfg(windows))] fn test_rw_arc_poison_wr() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); -- cgit 1.4.1-3-g733a5