This commit is contained in:
@@ -152,7 +152,7 @@ fn to_uint<T>(thing: &T) -> uint unsafe {
|
|||||||
|
|
||||||
/// Determine if two borrowed pointers point to the same thing.
|
/// Determine if two borrowed pointers point to the same thing.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ref_eq<T>(thing: &T, other: &T) -> bool {
|
fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
|
||||||
to_uint(thing) == to_uint(other)
|
to_uint(thing) == to_uint(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Unsafe operations
|
//! Unsafe operations
|
||||||
|
|
||||||
export reinterpret_cast, forget, bump_box_refcount, transmute;
|
export reinterpret_cast, forget, bump_box_refcount, transmute;
|
||||||
|
export transmute_mut, transmute_immut, transmute_region, transmute_mut_region;
|
||||||
|
|
||||||
export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
|
export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
|
||||||
export get_shared_mutable_state, get_shared_immutable_state;
|
export get_shared_mutable_state, get_shared_immutable_state;
|
||||||
@@ -53,6 +54,17 @@ unsafe fn transmute<L, G>(-thing: L) -> G {
|
|||||||
return newthing;
|
return newthing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Coerce an immutable reference to be mutable.
|
||||||
|
unsafe fn transmute_mut<T>(+ptr: &T) -> &mut T { transmute(ptr) }
|
||||||
|
/// Coerce a mutable reference to be immutable.
|
||||||
|
unsafe fn transmute_immut<T>(+ptr: &mut T) -> &T { transmute(ptr) }
|
||||||
|
/// Coerce a borrowed pointer to have an arbitrary associated region.
|
||||||
|
unsafe fn transmute_region<T>(+ptr: &a/T) -> &b/T { transmute(ptr) }
|
||||||
|
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
|
||||||
|
unsafe fn transmute_mut_region<T>(+ptr: &a/mut T) -> &b/mut T {
|
||||||
|
transmute(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Shared state & exclusive ARC
|
* Shared state & exclusive ARC
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import sync;
|
|||||||
import sync::{mutex, rwlock};
|
import sync::{mutex, rwlock};
|
||||||
|
|
||||||
export arc, clone, get;
|
export arc, clone, get;
|
||||||
export condvar, mutex_arc, rw_arc;
|
export condvar, mutex_arc, rw_arc, rw_write_mode, rw_read_mode;
|
||||||
|
|
||||||
/// As sync::condvar, a mechanism for unlock-and-descheduling and signalling.
|
/// As sync::condvar, a mechanism for unlock-and-descheduling and signalling.
|
||||||
struct condvar { is_mutex: bool; failed: &mut bool; cond: &sync::condvar; }
|
struct condvar { is_mutex: bool; failed: &mut bool; cond: &sync::condvar; }
|
||||||
@@ -136,10 +136,11 @@ impl<T: send> &mutex_arc<T> {
|
|||||||
&condvar { is_mutex: true, failed: &mut state.failed,
|
&condvar { is_mutex: true, failed: &mut state.failed,
|
||||||
cond: cond })
|
cond: cond })
|
||||||
*/
|
*/
|
||||||
// XXX: Working around two seeming region bugs here
|
// FIXME(#2282) region variance
|
||||||
let fref = unsafe { unsafe::reinterpret_cast(&mut state.failed) };
|
let fref =
|
||||||
|
unsafe { unsafe::transmute_mut_region(&mut state.failed) };
|
||||||
let cvar = condvar { is_mutex: true, failed: fref, cond: cond };
|
let cvar = condvar { is_mutex: true, failed: fref, cond: cond };
|
||||||
blk(&mut state.data, unsafe { unsafe::reinterpret_cast(&cvar) } )
|
blk(&mut state.data, unsafe { unsafe::transmute_region(&cvar) } )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,10 +228,12 @@ impl<T: const send> &rw_arc<T> {
|
|||||||
&condvar { is_mutex: false, failed: &mut state.failed,
|
&condvar { is_mutex: false, failed: &mut state.failed,
|
||||||
cond: cond })
|
cond: cond })
|
||||||
*/
|
*/
|
||||||
// XXX: Working around two seeming region bugs here
|
// FIXME(#2282): Need region variance to use the commented-out
|
||||||
let fref = unsafe { unsafe::reinterpret_cast(&mut state.failed) };
|
// code above instead of this casting mess
|
||||||
|
let fref =
|
||||||
|
unsafe { unsafe::transmute_mut_region(&mut state.failed) };
|
||||||
let cvar = condvar { is_mutex: false, failed: fref, cond: cond };
|
let cvar = condvar { is_mutex: false, failed: fref, cond: cond };
|
||||||
blk(&mut state.data, unsafe { unsafe::reinterpret_cast(&cvar) } )
|
blk(&mut state.data, unsafe { unsafe::transmute_region(&cvar) } )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -249,6 +252,52 @@ impl<T: const send> &rw_arc<T> {
|
|||||||
blk(&state.data)
|
blk(&state.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As write(), but with the ability to atomically 'downgrade' the lock.
|
||||||
|
* See sync::rwlock.write_downgrade(). The rw_write_mode token must be
|
||||||
|
* used to obtain the &mut T, and can be transformed into a rw_read_mode
|
||||||
|
* token by calling downgrade(), after which a &T can be obtained instead.
|
||||||
|
* ~~~
|
||||||
|
* do arc.write_downgrade |write_mode| {
|
||||||
|
* do (&write_mode).write_cond |state, condvar| {
|
||||||
|
* ... exclusive access with mutable state ...
|
||||||
|
* }
|
||||||
|
* let read_mode = arc.downgrade(write_mode);
|
||||||
|
* do (&read_mode).read |state| {
|
||||||
|
* ... shared access with immutable state ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
fn write_downgrade<U>(blk: fn(+rw_write_mode<T>) -> U) -> U {
|
||||||
|
let state = unsafe { get_shared_mutable_state(&self.x) };
|
||||||
|
do borrow_rwlock(state).write_downgrade |write_mode| {
|
||||||
|
check_poison(false, state.failed);
|
||||||
|
// FIXME(#2282) need region variance to avoid having to cast here
|
||||||
|
let (data,failed) =
|
||||||
|
unsafe { (unsafe::transmute_mut_region(&mut state.data),
|
||||||
|
unsafe::transmute_mut_region(&mut state.failed)) };
|
||||||
|
blk(rw_write_mode((data, write_mode, poison_on_fail(failed))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To be called inside of the write_downgrade block.
|
||||||
|
fn downgrade(+token: rw_write_mode<T>) -> rw_read_mode<T> {
|
||||||
|
// The rwlock should assert that the token belongs to us for us.
|
||||||
|
let state = unsafe { get_shared_immutable_state(&self.x) };
|
||||||
|
let rw_write_mode((data, t, _poison)) = token;
|
||||||
|
// Let readers in
|
||||||
|
let new_token = (&state.lock).downgrade(t);
|
||||||
|
// Whatever region the input reference had, it will be safe to use
|
||||||
|
// the same region for the output reference. (The only 'unsafe' part
|
||||||
|
// of this cast is removing the mutability.)
|
||||||
|
let new_data = unsafe { unsafe::transmute_immut(data) };
|
||||||
|
// Downgrade ensured the token belonged to us. Just a sanity check.
|
||||||
|
assert ptr::ref_eq(&state.data, new_data);
|
||||||
|
// Produce new token
|
||||||
|
rw_read_mode((new_data, new_token))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Borrowck rightly complains about immutably aliasing the rwlock in order to
|
// Borrowck rightly complains about immutably aliasing the rwlock in order to
|
||||||
@@ -258,6 +307,58 @@ fn borrow_rwlock<T: const send>(state: &mut rw_arc_inner<T>) -> &rwlock {
|
|||||||
unsafe { unsafe::reinterpret_cast(&state.lock) }
|
unsafe { unsafe::reinterpret_cast(&state.lock) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.
|
||||||
|
|
||||||
|
/// The "write permission" token used for rw_arc.write_downgrade().
|
||||||
|
enum rw_write_mode<T: const send> =
|
||||||
|
(&mut T, sync::rwlock_write_mode, poison_on_fail);
|
||||||
|
/// The "read permission" token used for rw_arc.write_downgrade().
|
||||||
|
enum rw_read_mode<T:const send> = (&T, sync::rwlock_read_mode);
|
||||||
|
|
||||||
|
impl<T: const send> &rw_write_mode<T> {
|
||||||
|
/// Access the pre-downgrade rw_arc in write mode.
|
||||||
|
fn write<U>(blk: fn(x: &mut T) -> U) -> U {
|
||||||
|
match *self {
|
||||||
|
rw_write_mode((data, ref token, _)) => {
|
||||||
|
// FIXME(#2282) cast to avoid region invariance
|
||||||
|
let mode = unsafe { unsafe::transmute_region(token) };
|
||||||
|
do mode.write {
|
||||||
|
blk(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Access the pre-downgrade rw_arc in write mode with a condvar.
|
||||||
|
fn write_cond<U>(blk: fn(x: &x/mut T, c: &c/condvar) -> U) -> U {
|
||||||
|
match *self {
|
||||||
|
rw_write_mode((data, ref token, ref poison)) => {
|
||||||
|
// FIXME(#2282) cast to avoid region invariance
|
||||||
|
let mode = unsafe { unsafe::transmute_region(token) };
|
||||||
|
do mode.write_cond |cond| {
|
||||||
|
let cvar = condvar {
|
||||||
|
is_mutex: false, failed: poison.failed,
|
||||||
|
cond: unsafe { unsafe::reinterpret_cast(cond) } };
|
||||||
|
// FIXME(#2282) region variance would avoid having to cast
|
||||||
|
blk(data, &cvar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: const send> &rw_read_mode<T> {
|
||||||
|
/// Access the post-downgrade rwlock in read mode.
|
||||||
|
fn read<U>(blk: fn(x: &T) -> U) -> U {
|
||||||
|
match *self {
|
||||||
|
rw_read_mode((data, ref token)) => {
|
||||||
|
// FIXME(#2282) cast to avoid region invariance
|
||||||
|
let mode = unsafe { unsafe::transmute_region(token) };
|
||||||
|
do mode.read { blk(data) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Tests
|
* Tests
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -374,6 +475,23 @@ mod tests {
|
|||||||
assert *one == 1;
|
assert *one == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[test] #[should_fail] #[ignore(cfg(windows))]
|
||||||
|
fn test_rw_arc_poison_dw() {
|
||||||
|
let arc = ~rw_arc(1);
|
||||||
|
let arc2 = ~arc.clone();
|
||||||
|
do task::try {
|
||||||
|
do arc2.write_downgrade |write_mode| {
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&write_mode) };
|
||||||
|
do mode.write |one| {
|
||||||
|
assert *one == 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
do arc.write |one| {
|
||||||
|
assert *one == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
#[test] #[ignore(cfg(windows))]
|
#[test] #[ignore(cfg(windows))]
|
||||||
fn test_rw_arc_no_poison_rr() {
|
fn test_rw_arc_no_poison_rr() {
|
||||||
let arc = ~rw_arc(1);
|
let arc = ~rw_arc(1);
|
||||||
@@ -400,7 +518,24 @@ mod tests {
|
|||||||
assert *one == 1;
|
assert *one == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[test] #[ignore(cfg(windows))]
|
||||||
|
fn test_rw_arc_no_poison_dr() {
|
||||||
|
let arc = ~rw_arc(1);
|
||||||
|
let arc2 = ~arc.clone();
|
||||||
|
do task::try {
|
||||||
|
do arc2.write_downgrade |write_mode| {
|
||||||
|
let read_mode = arc2.downgrade(write_mode);
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&read_mode) };
|
||||||
|
do mode.read |one| {
|
||||||
|
assert *one == 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
do arc.write |one| {
|
||||||
|
assert *one == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rw_arc() {
|
fn test_rw_arc() {
|
||||||
let arc = ~rw_arc(0);
|
let arc = ~rw_arc(0);
|
||||||
@@ -434,4 +569,84 @@ mod tests {
|
|||||||
p.recv();
|
p.recv();
|
||||||
do arc.read |num| { assert *num == 10; }
|
do arc.read |num| { assert *num == 10; }
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_rw_downgrade() {
|
||||||
|
// (1) A downgrader gets in write mode and does cond.wait.
|
||||||
|
// (2) A writer gets in write mode, sets state to 42, and does signal.
|
||||||
|
// (3) Downgrader wakes, sets state to 31337.
|
||||||
|
// (4) tells writer and all other readers to contend as it downgrades.
|
||||||
|
// (5) Writer attempts to set state back to 42, while downgraded task
|
||||||
|
// and all reader tasks assert that it's 31337.
|
||||||
|
let arc = ~rw_arc(0);
|
||||||
|
|
||||||
|
// Reader tasks
|
||||||
|
let mut reader_convos = ~[];
|
||||||
|
for 10.times {
|
||||||
|
let ((rc1,rp1),(rc2,rp2)) = (pipes::stream(),pipes::stream());
|
||||||
|
vec::push(reader_convos, (rc1,rp2));
|
||||||
|
let arcn = ~arc.clone();
|
||||||
|
do task::spawn {
|
||||||
|
rp1.recv(); // wait for downgrader to give go-ahead
|
||||||
|
do arcn.read |state| {
|
||||||
|
assert *state == 31337;
|
||||||
|
rc2.send(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writer task
|
||||||
|
let arc2 = ~arc.clone();
|
||||||
|
let ((wc1,wp1),(wc2,wp2)) = (pipes::stream(),pipes::stream());
|
||||||
|
do task::spawn {
|
||||||
|
wp1.recv();
|
||||||
|
do arc2.write_cond |state, cond| {
|
||||||
|
assert *state == 0;
|
||||||
|
*state = 42;
|
||||||
|
cond.signal();
|
||||||
|
}
|
||||||
|
wp1.recv();
|
||||||
|
do arc2.write |state| {
|
||||||
|
// This shouldn't happen until after the downgrade read
|
||||||
|
// section, and all other readers, finish.
|
||||||
|
assert *state == 31337;
|
||||||
|
*state = 42;
|
||||||
|
}
|
||||||
|
wc2.send(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Downgrader (us)
|
||||||
|
do arc.write_downgrade |write_mode| {
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&write_mode) };
|
||||||
|
do mode.write_cond |state, cond| {
|
||||||
|
wc1.send(()); // send to another writer who will wake us up
|
||||||
|
while *state == 0 {
|
||||||
|
cond.wait();
|
||||||
|
}
|
||||||
|
assert *state == 42;
|
||||||
|
*state = 31337;
|
||||||
|
// send to other readers
|
||||||
|
for vec::each(reader_convos) |x| {
|
||||||
|
match x {
|
||||||
|
(rc, _) => rc.send(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let read_mode = arc.downgrade(write_mode);
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&read_mode) };
|
||||||
|
do mode.read |state| {
|
||||||
|
// complete handshake with other readers
|
||||||
|
for vec::each(reader_convos) |x| {
|
||||||
|
match x {
|
||||||
|
(_, rp) => rp.recv(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wc1.send(()); // tell writer to try again
|
||||||
|
assert *state == 31337;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp2.recv(); // complete handshake with writer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* in std.
|
* in std.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export condvar, semaphore, mutex, rwlock;
|
export condvar, semaphore, mutex, rwlock, rwlock_write_mode, rwlock_read_mode;
|
||||||
|
|
||||||
// FIXME (#3119) This shouldn't be a thing exported from core.
|
// FIXME (#3119) This shouldn't be a thing exported from core.
|
||||||
import unsafe::{Exclusive, exclusive};
|
import unsafe::{Exclusive, exclusive};
|
||||||
@@ -387,7 +387,7 @@ impl &rwlock {
|
|||||||
* the meantime (such as unlocking and then re-locking as a reader would
|
* the meantime (such as unlocking and then re-locking as a reader would
|
||||||
* do). The block takes a "write mode token" argument, which can be
|
* do). The block takes a "write mode token" argument, which can be
|
||||||
* transformed into a "read mode token" by calling downgrade(). Example:
|
* transformed into a "read mode token" by calling downgrade(). Example:
|
||||||
*
|
* ~~~
|
||||||
* do lock.write_downgrade |write_mode| {
|
* do lock.write_downgrade |write_mode| {
|
||||||
* do (&write_mode).write_cond |condvar| {
|
* do (&write_mode).write_cond |condvar| {
|
||||||
* ... exclusive access ...
|
* ... exclusive access ...
|
||||||
@@ -397,6 +397,7 @@ impl &rwlock {
|
|||||||
* ... shared access ...
|
* ... shared access ...
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
|
* ~~~
|
||||||
*/
|
*/
|
||||||
fn write_downgrade<U>(blk: fn(+rwlock_write_mode) -> U) -> U {
|
fn write_downgrade<U>(blk: fn(+rwlock_write_mode) -> U) -> U {
|
||||||
// Implementation slightly different from the slicker 'write's above.
|
// Implementation slightly different from the slicker 'write's above.
|
||||||
@@ -413,6 +414,7 @@ impl &rwlock {
|
|||||||
blk(rwlock_write_mode { lock: self })
|
blk(rwlock_write_mode { lock: self })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// To be called inside of the write_downgrade block.
|
||||||
fn downgrade(+token: rwlock_write_mode) -> rwlock_read_mode {
|
fn downgrade(+token: rwlock_write_mode) -> rwlock_read_mode {
|
||||||
if !ptr::ref_eq(self, token.lock) {
|
if !ptr::ref_eq(self, token.lock) {
|
||||||
fail ~"Can't downgrade() with a different rwlock's write_mode!";
|
fail ~"Can't downgrade() with a different rwlock's write_mode!";
|
||||||
@@ -498,8 +500,7 @@ struct rwlock_write_mode { lock: &rwlock; drop { } }
|
|||||||
/// The "read permission" token used for rwlock.write_downgrade().
|
/// The "read permission" token used for rwlock.write_downgrade().
|
||||||
struct rwlock_read_mode { priv lock: &rwlock; drop { } }
|
struct rwlock_read_mode { priv lock: &rwlock; drop { } }
|
||||||
|
|
||||||
// FIXME(#3145) XXX Region invariance forbids "mode.write(blk)"
|
impl &rwlock_write_mode {
|
||||||
impl rwlock_write_mode {
|
|
||||||
/// Access the pre-downgrade rwlock in write mode.
|
/// Access the pre-downgrade rwlock in write mode.
|
||||||
fn write<U>(blk: fn() -> U) -> U { blk() }
|
fn write<U>(blk: fn() -> U) -> U { blk() }
|
||||||
/// Access the pre-downgrade rwlock in write mode with a condvar.
|
/// Access the pre-downgrade rwlock in write mode with a condvar.
|
||||||
@@ -507,7 +508,7 @@ impl rwlock_write_mode {
|
|||||||
blk(&condvar { sem: &self.lock.access_lock })
|
blk(&condvar { sem: &self.lock.access_lock })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl rwlock_read_mode {
|
impl &rwlock_read_mode {
|
||||||
/// Access the post-downgrade rwlock in read mode.
|
/// Access the post-downgrade rwlock in read mode.
|
||||||
fn read<U>(blk: fn() -> U) -> U { blk() }
|
fn read<U>(blk: fn() -> U) -> U { blk() }
|
||||||
}
|
}
|
||||||
@@ -777,9 +778,19 @@ mod tests {
|
|||||||
match mode {
|
match mode {
|
||||||
read => x.read(blk),
|
read => x.read(blk),
|
||||||
write => x.write(blk),
|
write => x.write(blk),
|
||||||
downgrade => do x.write_downgrade |mode| { mode.write(blk); },
|
downgrade =>
|
||||||
|
do x.write_downgrade |mode| {
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&mode) };
|
||||||
|
mode.write(blk);
|
||||||
|
},
|
||||||
downgrade_read =>
|
downgrade_read =>
|
||||||
do x.write_downgrade |mode| { x.downgrade(mode).read(blk); },
|
do x.write_downgrade |mode| {
|
||||||
|
let mode = x.downgrade(mode);
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&mode) };
|
||||||
|
mode.read(blk);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -922,7 +933,11 @@ mod tests {
|
|||||||
// Much like the mutex broadcast test. Downgrade-enabled.
|
// Much like the mutex broadcast test. Downgrade-enabled.
|
||||||
fn lock_cond(x: &rwlock, downgrade: bool, blk: fn(c: &condvar)) {
|
fn lock_cond(x: &rwlock, downgrade: bool, blk: fn(c: &condvar)) {
|
||||||
if downgrade {
|
if downgrade {
|
||||||
do x.write_downgrade |mode| { mode.write_cond(blk) }
|
do x.write_downgrade |mode| {
|
||||||
|
// FIXME(#2282)
|
||||||
|
let mode = unsafe { unsafe::transmute_region(&mode) };
|
||||||
|
mode.write_cond(blk)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
x.write_cond(blk)
|
x.write_cond(blk)
|
||||||
}
|
}
|
||||||
@@ -1009,10 +1024,9 @@ mod tests {
|
|||||||
do x.write_downgrade |xwrite| {
|
do x.write_downgrade |xwrite| {
|
||||||
let mut xopt = some(xwrite);
|
let mut xopt = some(xwrite);
|
||||||
do y.write_downgrade |_ywrite| {
|
do y.write_downgrade |_ywrite| {
|
||||||
do y.downgrade(option::swap_unwrap(&mut xopt)).read {
|
y.downgrade(option::swap_unwrap(&mut xopt));
|
||||||
error!("oops, y.downgrade(x) should have failed!");
|
error!("oops, y.downgrade(x) should have failed!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs
Normal file
11
src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::arc;
|
||||||
|
fn main() {
|
||||||
|
let x = ~arc::rw_arc(1);
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_cond |_one, cond| {
|
||||||
|
y = some(cond);
|
||||||
|
}
|
||||||
|
option::unwrap(y).wait();
|
||||||
|
}
|
||||||
12
src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs
Normal file
12
src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::arc;
|
||||||
|
fn main() {
|
||||||
|
let x = ~arc::rw_arc(1);
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
y = some(x.downgrade(write_mode));
|
||||||
|
}
|
||||||
|
// Adding this line causes a method unification failure instead
|
||||||
|
// do (&option::unwrap(y)).read |state| { assert *state == 1; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::arc;
|
||||||
|
fn main() {
|
||||||
|
let x = ~arc::rw_arc(1);
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
do (&write_mode).write_cond |_one, cond| {
|
||||||
|
y = some(cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
option::unwrap(y).wait();
|
||||||
|
}
|
||||||
12
src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs
Normal file
12
src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::arc;
|
||||||
|
fn main() {
|
||||||
|
let x = ~arc::rw_arc(1);
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
y = some(write_mode);
|
||||||
|
}
|
||||||
|
// Adding this line causes a method unification failure instead
|
||||||
|
// do (&option::unwrap(y)).write |state| { assert *state == 1; }
|
||||||
|
}
|
||||||
11
src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs
Normal file
11
src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::sync;
|
||||||
|
fn main() {
|
||||||
|
let x = ~sync::rwlock();
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_cond |cond| {
|
||||||
|
y = some(cond);
|
||||||
|
}
|
||||||
|
option::unwrap(y).wait();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::sync;
|
||||||
|
fn main() {
|
||||||
|
let x = ~sync::rwlock();
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
y = some(x.downgrade(write_mode));
|
||||||
|
}
|
||||||
|
// Adding this line causes a method unification failure instead
|
||||||
|
// do (&option::unwrap(y)).read { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::sync;
|
||||||
|
fn main() {
|
||||||
|
let x = ~sync::rwlock();
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
do (&write_mode).write_cond |cond| {
|
||||||
|
y = some(cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
option::unwrap(y).wait();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// error-pattern: reference is not valid outside of its lifetime
|
||||||
|
use std;
|
||||||
|
import std::sync;
|
||||||
|
fn main() {
|
||||||
|
let x = ~sync::rwlock();
|
||||||
|
let mut y = none;
|
||||||
|
do x.write_downgrade |write_mode| {
|
||||||
|
y = some(write_mode);
|
||||||
|
}
|
||||||
|
// Adding this line causes a method unification failure instead
|
||||||
|
// do (&option::unwrap(y)).write { }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user