From be2e4ef624acdeb260bc1ba86e9a357b30775baa Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Thu, 9 Aug 2012 14:55:54 -0400 Subject: [PATCH] Allow failing in arc::exclusive; poison to fail subsequent accesses (fix #3092) --- src/libcore/arc.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs index ab16750b8da..fe359646868 100644 --- a/src/libcore/arc.rs +++ b/src/libcore/arc.rs @@ -81,11 +81,12 @@ fn clone(rc: &arc) -> arc { } // An arc over mutable data that is protected by a lock. -type ex_data = {lock: sys::little_lock, mut data: T}; +type ex_data = + {lock: sys::little_lock, mut failed: bool, mut data: T}; type exclusive = arc_destruct>; fn exclusive(-data: T) -> exclusive { - let data = ~{mut count: 1, data: {lock: sys::little_lock(), + let data = ~{mut count: 1, data: {lock: sys::little_lock(), failed: false, data: data}}; unsafe { let ptr = unsafe::reinterpret_cast(data); @@ -128,12 +129,18 @@ impl exclusive { let ptr: ~arc_data> = unsafe::reinterpret_cast(self.data); assert ptr.count > 0; - let r = { - let rec: &ex_data = &(*ptr).data; - do rec.lock.lock { f(&mut rec.data) } - }; + let ptr2: &arc_data> = unsafe::reinterpret_cast(&*ptr); unsafe::forget(ptr); - r + let rec: &ex_data = &(*ptr2).data; + do rec.lock.lock { + if rec.failed { + fail ~"Poisoned arc::exclusive - another task failed inside!"; + } + rec.failed = true; + let result = f(&mut rec.data); + rec.failed = false; + result + } } } @@ -168,12 +175,11 @@ mod tests { } #[test] - #[ignore] // this can probably infinite loop too. fn exclusive_arc() { let mut futures = ~[]; let num_tasks = 10u; - let count = 1000u; + let count = 10u; let total = exclusive(~mut 0u); @@ -194,4 +200,20 @@ mod tests { assert **total == num_tasks * count }; } + + #[test] #[should_fail] #[ignore(cfg(windows))] + fn exclusive_poison() { + // Tests that if one task fails inside of an exclusive, subsequent + // accesses will also fail. + let x = arc::exclusive(1); + let x2 = x.clone(); + do task::try { + do x2.with |one| { + assert *one == 2; + } + }; + do x.with |one| { + assert *one == 1; + } + } }