auto merge of #12336 : kballard/rust/mutexarc-no-freeze, r=alexcrichton

With Rc no longer trying to statically prevent cycles (and thus no
longer using the Freeze bound), it seems appropriate to remove that
restriction from MutexArc as well.

Closes #9251.
This commit is contained in:
bors 2014-02-18 10:16:48 -08:00
commit a886549772
2 changed files with 34 additions and 99 deletions

View File

@ -192,12 +192,6 @@ impl<T:Send> MutexArc<T> {
* other tasks wishing to access the data will block until the closure
* finishes running.
*
* The reason this function is 'unsafe' is because it is possible to
* construct a circular reference among multiple Arcs by mutating the
* underlying data. This creates potential for deadlock, but worse, this
* will guarantee a memory leak of all involved Arcs. Using MutexArcs
* inside of other Arcs is safe in absence of circular references.
*
* If you wish to nest MutexArcs, one strategy for ensuring safety at
* runtime is to add a "nesting level counter" inside the stored data, and
* when traversing the arcs, assert that they monotonically decrease.
@ -210,63 +204,33 @@ impl<T:Send> MutexArc<T> {
* blocked on the mutex) will also fail immediately.
*/
#[inline]
pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
let state = self.x.get();
// Borrowck would complain about this if the function were
// not already unsafe. See borrow_rwlock, far below.
(&(*state).lock).lock(|| {
check_poison(true, (*state).failed);
let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data)
})
}
/// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
#[inline]
pub unsafe fn unsafe_access_cond<U>(&self,
blk: |x: &mut T, c: &Condvar| -> U)
-> U {
let state = self.x.get();
(&(*state).lock).lock_cond(|cond| {
check_poison(true, (*state).failed);
let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data,
&Condvar {is_mutex: true,
failed: &(*state).failed,
cond: cond })
})
}
}
impl<T:Freeze + Send> MutexArc<T> {
/**
* As unsafe_access.
*
* The difference between access and unsafe_access is that the former
* forbids mutexes to be nested. While unsafe_access can be used on
* MutexArcs without freezable interiors, this safe version of access
* requires the Freeze bound, which prohibits access on MutexArcs which
* might contain nested MutexArcs inside.
*
* The purpose of this is to offer a safe implementation of MutexArc to be
* used instead of RWArc in cases where no readers are needed and slightly
* better performance is required.
*
* Both methods have the same failure behaviour as unsafe_access and
* unsafe_access_cond.
*/
#[inline]
pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
unsafe { self.unsafe_access(blk) }
let state = self.x.get();
unsafe {
// Borrowck would complain about this if the code were
// not already unsafe. See borrow_rwlock, far below.
(&(*state).lock).lock(|| {
check_poison(true, (*state).failed);
let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data)
})
}
}
/// As unsafe_access_cond but safe and Freeze.
/// As access(), but with a condvar, as sync::mutex.lock_cond().
#[inline]
pub fn access_cond<U>(&self,
blk: |x: &mut T, c: &Condvar| -> U)
-> U {
unsafe { self.unsafe_access_cond(blk) }
pub fn access_cond<U>(&self, blk: |x: &mut T, c: &Condvar| -> U) -> U {
let state = self.x.get();
unsafe {
(&(*state).lock).lock_cond(|cond| {
check_poison(true, (*state).failed);
let _z = PoisonOnFail::new(&mut (*state).failed);
blk(&mut (*state).data,
&Condvar {is_mutex: true,
failed: &(*state).failed,
cond: cond })
})
}
}
}
@ -590,7 +554,6 @@ impl<T:Clone+Send+Freeze> CowArc<T> {
impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
/// Duplicate a Copy-on-write Arc. See arc::clone for more details.
#[inline]
fn clone(&self) -> CowArc<T> {
CowArc { x: self.x.clone() }
}
@ -692,20 +655,18 @@ mod tests {
}
#[test]
fn test_unsafe_mutex_arc_nested() {
unsafe {
// Tests nested mutexes and access
// to underlaying data.
let arc = ~MutexArc::new(1);
let arc2 = ~MutexArc::new(*arc);
task::spawn(proc() {
(*arc2).unsafe_access(|mutex| {
(*mutex).access(|one| {
assert!(*one == 1);
})
fn test_mutex_arc_nested() {
// Tests nested mutexes and access
// to underlaying data.
let arc = ~MutexArc::new(1);
let arc2 = ~MutexArc::new(*arc);
task::spawn(proc() {
(*arc2).access(|mutex| {
(*mutex).access(|one| {
assert!(*one == 1);
})
});
}
})
});
}
#[test]

View File

@ -1,26 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate sync;
use std::task;
use sync::MutexArc;
fn test_mutex_arc_nested() {
let arc = ~MutexArc::new(1);
let arc2 = ~MutexArc::new(*arc);
task::spawn(proc() {
(*arc2).access(|mutex| { //~ ERROR instantiating a type parameter with an incompatible type
})
});
}
fn main() {}