1
Fork 0

Don't poison ARCs that are used while unwinding

Closes #11097
This commit is contained in:
Steven Fackler 2013-12-21 20:53:43 -07:00
parent ba801d8116
commit 7a1e486b2a

View file

@ -226,7 +226,7 @@ impl<T:Send> MutexArc<T> {
// not already unsafe. See borrow_rwlock, far below. // not already unsafe. See borrow_rwlock, far below.
(&(*state).lock).lock(|| { (&(*state).lock).lock(|| {
check_poison(true, (*state).failed); check_poison(true, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed); let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data) blk(&mut (*state).data)
}) })
} }
@ -239,7 +239,7 @@ impl<T:Send> MutexArc<T> {
let state = self.x.get(); let state = self.x.get();
(&(*state).lock).lock_cond(|cond| { (&(*state).lock).lock_cond(|cond| {
check_poison(true, (*state).failed); check_poison(true, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed); let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data, blk(&mut (*state).data,
&Condvar {is_mutex: true, &Condvar {is_mutex: true,
failed: &mut (*state).failed, failed: &mut (*state).failed,
@ -311,7 +311,8 @@ fn check_poison(is_mutex: bool, failed: bool) {
#[doc(hidden)] #[doc(hidden)]
struct PoisonOnFail { struct PoisonOnFail {
failed: *mut bool, flag: *mut bool,
failed: bool,
} }
impl Drop for PoisonOnFail { impl Drop for PoisonOnFail {
@ -319,16 +320,19 @@ impl Drop for PoisonOnFail {
unsafe { unsafe {
/* assert!(!*self.failed); /* assert!(!*self.failed);
-- might be false in case of cond.wait() */ -- might be false in case of cond.wait() */
if task::failing() { if !self.failed && task::failing() {
*self.failed = true; *self.flag = true;
} }
} }
} }
} }
fn PoisonOnFail<'r>(failed: &'r mut bool) -> PoisonOnFail { impl PoisonOnFail {
PoisonOnFail { fn new<'a>(flag: &'a mut bool) -> PoisonOnFail {
failed: failed PoisonOnFail {
flag: flag,
failed: task::failing()
}
} }
} }
@ -392,7 +396,7 @@ impl<T:Freeze + Send> RWArc<T> {
let state = self.x.get(); let state = self.x.get();
(*borrow_rwlock(state)).write(|| { (*borrow_rwlock(state)).write(|| {
check_poison(false, (*state).failed); check_poison(false, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed); let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data) blk(&mut (*state).data)
}) })
} }
@ -407,7 +411,7 @@ impl<T:Freeze + Send> RWArc<T> {
let state = self.x.get(); let state = self.x.get();
(*borrow_rwlock(state)).write_cond(|cond| { (*borrow_rwlock(state)).write_cond(|cond| {
check_poison(false, (*state).failed); check_poison(false, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed); let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data, blk(&mut (*state).data,
&Condvar {is_mutex: false, &Condvar {is_mutex: false,
failed: &mut (*state).failed, failed: &mut (*state).failed,
@ -463,7 +467,7 @@ impl<T:Freeze + Send> RWArc<T> {
blk(RWWriteMode { blk(RWWriteMode {
data: &mut (*state).data, data: &mut (*state).data,
token: write_mode, token: write_mode,
poison: PoisonOnFail(&mut (*state).failed) poison: PoisonOnFail::new(&mut (*state).failed)
}) })
}) })
} }
@ -563,7 +567,7 @@ impl<'a, T:Freeze + Send> RWWriteMode<'a, T> {
unsafe { unsafe {
let cvar = Condvar { let cvar = Condvar {
is_mutex: false, is_mutex: false,
failed: &mut *poison.failed, failed: &mut *poison.flag,
cond: cond cond: cond
}; };
blk(data, &cvar) blk(data, &cvar)
@ -714,6 +718,25 @@ mod tests {
} }
} }
#[test]
fn test_mutex_arc_access_in_unwind() {
let arc = MutexArc::new(1i);
let arc2 = arc.clone();
task::try::<()>(proc() {
struct Unwinder {
i: MutexArc<int>
}
impl Drop for Unwinder {
fn drop(&mut self) {
self.i.access(|num| *num += 1);
}
}
let _u = Unwinder { i: arc2 };
fail!();
});
assert_eq!(2, arc.access(|n| *n));
}
#[test] #[should_fail] #[test] #[should_fail]
fn test_rw_arc_poison_wr() { fn test_rw_arc_poison_wr() {
let arc = RWArc::new(1); let arc = RWArc::new(1);
@ -840,6 +863,26 @@ mod tests {
assert_eq!(*num, 10); assert_eq!(*num, 10);
}) })
} }
#[test]
fn test_rw_arc_access_in_unwind() {
let arc = RWArc::new(1i);
let arc2 = arc.clone();
task::try::<()>(proc() {
struct Unwinder {
i: RWArc<int>
}
impl Drop for Unwinder {
fn drop(&mut self) {
self.i.write(|num| *num += 1);
}
}
let _u = Unwinder { i: arc2 };
fail!();
});
assert_eq!(2, arc.read(|n| *n));
}
#[test] #[test]
fn test_rw_downgrade() { fn test_rw_downgrade() {
// (1) A downgrader gets in write mode and does cond.wait. // (1) A downgrader gets in write mode and does cond.wait.