diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-01-09 13:47:37 -0800 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-01-09 19:53:32 -0800 |
| commit | 110c3ccdcad4616fd558f248b61a4ba79d8ec86b (patch) | |
| tree | e211c5b764ed6899c2ecf55047ee1a15886b722e | |
| parent | 005e3194858785e9debae8116caedf4c14e3b727 (diff) | |
| download | rust-110c3ccdcad4616fd558f248b61a4ba79d8ec86b.tar.gz rust-110c3ccdcad4616fd558f248b61a4ba79d8ec86b.zip | |
add rust_task_is_unwinding predicate and do not kill if already unwinding
| -rw-r--r-- | src/libcore/task.rs | 14 | ||||
| -rw-r--r-- | src/rt/rust_task.cpp | 27 | ||||
| -rw-r--r-- | src/rt/rust_task.h | 6 | ||||
| -rw-r--r-- | src/rt/rustrt.def.in | 1 | ||||
| -rw-r--r-- | src/test/run-pass/task-killjoin-rsrc.rs | 16 |
5 files changed, 47 insertions, 17 deletions
diff --git a/src/libcore/task.rs b/src/libcore/task.rs index 19e3f2b21b3..2a9a39e0aaa 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -49,6 +49,7 @@ export spawn_joinable; export spawn_connected; export connected_fn; export connected_task; +export currently_unwinding; #[abi = "rust-intrinsic"] native mod rusti { @@ -76,6 +77,8 @@ native mod rustrt { fn migrate_alloc(alloc: *u8, target: task_id); fn start_task(id: task, closure: *rust_closure); + + fn rust_task_is_unwinding(rt: *rust_task) -> bool; } /* Section: Types */ @@ -271,7 +274,7 @@ fn sleep(time_in_us: uint) { // in a snapshot. // #debug("yielding for %u us", time_in_us); rusti::task_sleep(task, time_in_us, killed); - if killed { + if killed && !currently_unwinding() { fail "killed"; } } @@ -337,6 +340,15 @@ Unpin the current task and future child tasks */ fn unpin() { rustrt::unpin_task(); } +/* +Function: currently_unwinding() + +True if we are currently unwinding after a failure. +*/ +fn currently_unwinding() -> bool { + rustrt::rust_task_is_unwinding(rustrt::rust_get_task()) +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index edb356a9609..eb3040ebfae 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -245,7 +245,7 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state, running_on(-1), pinned_on(-1), local_region(&sched->srv->local_region), - failed(false), + unwinding(false), killed(false), propagate_failure(true), dynastack(this), @@ -299,27 +299,27 @@ struct spawn_args { struct cleanup_args { spawn_args *spargs; - bool failed; + bool threw_exception; }; void cleanup_task(cleanup_args *args) { spawn_args *a = args->spargs; - bool failed = args->failed; + bool threw_exception = args->threw_exception; rust_task *task = a->task; cc::do_cc(task); task->die(); - if (task->killed && !failed) { + if (task->killed && !threw_exception) { LOG(task, task, "Task killed during termination"); - failed = true; + threw_exception = true; } - task->notify(!failed); + task->notify(!threw_exception); - if (failed) { + if (threw_exception) { #ifndef __WIN32__ task->conclude_failure(); #else @@ -336,7 +336,7 @@ void task_start_wrapper(spawn_args *a) { rust_task *task = a->task; - bool failed = false; + bool threw_exception = false; try { // The first argument is the return pointer; as the task fn // must have void return type, we can safely pass 0. @@ -344,7 +344,7 @@ void task_start_wrapper(spawn_args *a) } catch (rust_task *ex) { A(task->sched, ex == task, "Expected this task to be thrown for unwinding"); - failed = true; + threw_exception = true; } rust_opaque_closure* env = a->envptr; @@ -357,7 +357,7 @@ void task_start_wrapper(spawn_args *a) } // The cleanup work needs lots of stack - cleanup_args ca = {a, failed}; + cleanup_args ca = {a, threw_exception}; task->sched->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task); task->ctx.next->swap(task->ctx); @@ -437,11 +437,17 @@ rust_task::kill() { // run_on_resume(rust_unwind_glue); } +extern "C" CDECL +bool rust_task_is_unwinding(rust_task *rt) { + return rt->unwinding; +} + void rust_task::fail() { // See note in ::kill() regarding who should call this. DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this); backtrace(); + unwinding = true; #ifndef __WIN32__ throw this; #else @@ -455,7 +461,6 @@ rust_task::fail() { void rust_task::conclude_failure() { fail_parent(); - failed = true; } void diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index d0e3d0e2ad6..b47b62e2d14 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -107,8 +107,10 @@ rust_task : public kernel_owned<rust_task>, rust_cond memory_region local_region; - // Indicates that the task ended in failure - bool failed; + // Indicates that fail() has been called and we are cleaning up. + // We use this to suppress the "killed" flag during calls to yield. + bool unwinding; + // Indicates that the task was killed and needs to unwind bool killed; bool propagate_failure; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 86b41fcb256..8a44a7ab151 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -43,6 +43,7 @@ rust_ptr_eq rust_run_program rust_start rust_getcwd +rust_task_is_unwinding rust_task_sleep rust_get_task set_min_stack diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index 03aae01fb0b..f7829aa31df 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -10,18 +10,26 @@ fn joinable(f: fn()) -> (task::task, comm::port<bool>) { resource notify(data: (comm::chan<bool>, @mutable bool)) { let (c, v) = data; + #error["notify: task=%d v=%x unwinding=%b b=%b", + task::get_task(), + ptr::addr_of(*v) as uint, + task::currently_unwinding(), + *v]; comm::send(c, *v); } fn wrapper(pair: (comm::chan<bool>, fn())) { let (c, f) = pair; let b = @mutable false; + #error["wrapper: task=%d allocated v=%x", + task::get_task(), + ptr::addr_of(*b) as uint]; let _r = notify((c, b)); f(); *b = true; } let p = comm::port(); let c = comm::chan(p); - let t = task::spawn((c, f), wrapper); + let t = task::spawn {|| wrapper((c, f)) }; ret (t, p); } @@ -34,6 +42,7 @@ fn supervised() { // Yield to make sure the supervisor joins before we // fail. This is currently not needed because the supervisor // runs first, but I can imagine that changing. + #error["supervised task=%d", task::get_task()]; task::yield(); fail; } @@ -42,8 +51,9 @@ fn supervisor() { // Unsupervise this task so the process doesn't return a failure status as // a result of the main task being killed. task::unsupervise(); - let f = supervised; - join(joinable(supervised)); + #error["supervisor task=%d", task::get_task()]; + let t = joinable(supervised); + join(t); } fn main() { |
