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:
commit
a886549772
@ -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]
|
||||
|
@ -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() {}
|
Loading…
x
Reference in New Issue
Block a user