diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 661224b0a8037..83fd3b6bb06d4 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -48,6 +48,7 @@ use core::cast; use core::unstable::sync::UnsafeAtomicRcBox; use core::task; use core::borrow; +use core::util; /// As sync::condvar, a mechanism for unlock-and-descheduling and signaling. pub struct Condvar<'self> { @@ -332,6 +333,28 @@ impl RWARC { } } + /// As write(), but unpoisons poisoned ARCs. + #[inline] + pub fn unpoison(&self, blk: &fn() -> (T, U)) -> U { + unsafe { + let state = self.x.get(); + do (*borrow_rwlock(state)).write { + let _z = PoisonOnFail(&mut (*state).failed); + + let mut (writevalue, result) = blk(); + + util::swap(&mut (*state).data, &mut writevalue); + if (*state).failed { + // Might be uninitialized so is unsafe to destroy + cast::forget(writevalue) + } + (*state).failed = false; + + result + } + } + } + /// As write(), but with a condvar, as sync::rwlock.write_cond(). #[inline] pub fn write_cond<'x, 'c, U>(&self, @@ -736,6 +759,24 @@ mod tests { } } #[test] + fn test_rw_arc_unpoison() { + let arc = RWARC(0); + + // Poison the arc + let arc_clone = arc.clone(); + do task::spawn_unlinked { + do arc_clone.write |_| { + fail!() + } + } + + do arc.unpoison { (0, ()) } + + do arc.read |_| { + // Should succeed at reading the now unpoisoned value + } + } + #[test] fn test_rw_downgrade() { // (1) A downgrader gets in write mode and does cond.wait. // (2) A writer gets in write mode, sets state to 42, and does signal.