diff options
Diffstat (limited to 'src/libcore/task.rs')
| -rw-r--r-- | src/libcore/task.rs | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/src/libcore/task.rs b/src/libcore/task.rs index 7c3037606d9..6d6f82fde07 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -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 |
