* 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.
* blocked on the mutex) will also fail immediately.
*/
#[inline]
- pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
+ pub fn 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)
- })
+ 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(), but with a condvar, as sync::mutex.lock_cond().
+ /// As 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 {
+ pub fn 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) }
- }
-
- /// As unsafe_access_cond but safe and Freeze.
- #[inline]
- pub fn access_cond<U>(&self,
- blk: |x: &mut T, c: &Condvar| -> U)
- -> U {
- unsafe { self.unsafe_access_cond(blk) }
+ 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 })
+ })
+ }
}
}
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() }
}
}
#[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]