Add 'do atomically { .. }' for exclusives

This commit is contained in:
Ben Blum
2012-07-24 15:27:45 -04:00
parent 9103e43909
commit ae094a7adc
6 changed files with 91 additions and 13 deletions

View File

@@ -60,6 +60,7 @@ export yield;
export failing;
export get_task;
export unkillable;
export atomically;
export local_data_key;
export local_data_pop;
@@ -683,16 +684,36 @@ fn get_task() -> task {
*/
unsafe fn unkillable(f: fn()) {
class allow_failure {
let i: (); // since a class must have at least one field
new(_i: ()) { self.i = (); }
drop { rustrt::rust_task_allow_kill(); }
let t: *rust_task;
new(t: *rust_task) { self.t = t; }
drop { rustrt::rust_task_allow_kill(self.t); }
}
let _allow_failure = allow_failure(());
rustrt::rust_task_inhibit_kill();
let t = rustrt::rust_get_task();
let _allow_failure = allow_failure(t);
rustrt::rust_task_inhibit_kill(t);
f();
}
/**
* A stronger version of unkillable that also inhibits scheduling operations.
* For use with exclusive ARCs, which use pthread mutexes directly.
*/
unsafe fn atomically<U>(f: fn() -> U) -> U {
class defer_interrupts {
let t: *rust_task;
new(t: *rust_task) { self.t = t; }
drop {
rustrt::rust_task_allow_yield(self.t);
rustrt::rust_task_allow_kill(self.t);
}
}
let t = rustrt::rust_get_task();
let _interrupts = defer_interrupts(t);
rustrt::rust_task_inhibit_kill(t);
rustrt::rust_task_inhibit_yield(t);
f()
}
/****************************************************************************
* Internal
@@ -1235,8 +1256,10 @@ extern mod rustrt {
fn rust_task_is_unwinding(task: *rust_task) -> bool;
fn rust_osmain_sched_id() -> sched_id;
fn rust_task_inhibit_kill();
fn rust_task_allow_kill();
fn rust_task_inhibit_kill(t: *rust_task);
fn rust_task_allow_kill(t: *rust_task);
fn rust_task_inhibit_yield(t: *rust_task);
fn rust_task_allow_yield(t: *rust_task);
fn rust_task_kill_other(task: *rust_task);
fn rust_task_kill_all(task: *rust_task);
@@ -1759,6 +1782,21 @@ fn test_unkillable_nested() {
po.recv();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_atomically() {
unsafe { do atomically { yield(); } }
}
#[test]
fn test_atomically2() {
unsafe { do atomically { } } yield(); // shouldn't fail
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_atomically_nested() {
unsafe { do atomically { do atomically { } yield(); } }
}
#[test]
fn test_child_doesnt_ref_parent() {
// If the child refcounts the parent task, this will stack overflow when