Skip to content

Commit

Permalink
Remove Freeze bounds from sync::MutexArc
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lilyball committed Feb 17, 2014
1 parent c848906 commit 66bed17
Showing 1 changed file with 33 additions and 72 deletions.
105 changes: 33 additions & 72 deletions src/libsync/arc.rs
Expand Up @@ -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.
Expand All @@ -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 {
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 })
})
}
}
}

Expand Down Expand Up @@ -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() }
}
Expand Down Expand Up @@ -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]
Expand Down

0 comments on commit 66bed17

Please sign in to comment.