add rust_task_is_unwinding predicate and do not kill if already unwinding
This commit is contained in:
parent
005e319485
commit
110c3ccdca
5 changed files with 47 additions and 17 deletions
|
@ -49,6 +49,7 @@ export spawn_joinable;
|
||||||
export spawn_connected;
|
export spawn_connected;
|
||||||
export connected_fn;
|
export connected_fn;
|
||||||
export connected_task;
|
export connected_task;
|
||||||
|
export currently_unwinding;
|
||||||
|
|
||||||
#[abi = "rust-intrinsic"]
|
#[abi = "rust-intrinsic"]
|
||||||
native mod rusti {
|
native mod rusti {
|
||||||
|
@ -76,6 +77,8 @@ native mod rustrt {
|
||||||
fn migrate_alloc(alloc: *u8, target: task_id);
|
fn migrate_alloc(alloc: *u8, target: task_id);
|
||||||
|
|
||||||
fn start_task(id: task, closure: *rust_closure);
|
fn start_task(id: task, closure: *rust_closure);
|
||||||
|
|
||||||
|
fn rust_task_is_unwinding(rt: *rust_task) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Section: Types */
|
/* Section: Types */
|
||||||
|
@ -271,7 +274,7 @@ fn sleep(time_in_us: uint) {
|
||||||
// in a snapshot.
|
// in a snapshot.
|
||||||
// #debug("yielding for %u us", time_in_us);
|
// #debug("yielding for %u us", time_in_us);
|
||||||
rusti::task_sleep(task, time_in_us, killed);
|
rusti::task_sleep(task, time_in_us, killed);
|
||||||
if killed {
|
if killed && !currently_unwinding() {
|
||||||
fail "killed";
|
fail "killed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,6 +340,15 @@ Unpin the current task and future child tasks
|
||||||
*/
|
*/
|
||||||
fn unpin() { rustrt::unpin_task(); }
|
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:
|
// Local Variables:
|
||||||
// mode: rust;
|
// mode: rust;
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
|
@ -245,7 +245,7 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
|
||||||
running_on(-1),
|
running_on(-1),
|
||||||
pinned_on(-1),
|
pinned_on(-1),
|
||||||
local_region(&sched->srv->local_region),
|
local_region(&sched->srv->local_region),
|
||||||
failed(false),
|
unwinding(false),
|
||||||
killed(false),
|
killed(false),
|
||||||
propagate_failure(true),
|
propagate_failure(true),
|
||||||
dynastack(this),
|
dynastack(this),
|
||||||
|
@ -299,27 +299,27 @@ struct spawn_args {
|
||||||
|
|
||||||
struct cleanup_args {
|
struct cleanup_args {
|
||||||
spawn_args *spargs;
|
spawn_args *spargs;
|
||||||
bool failed;
|
bool threw_exception;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
cleanup_task(cleanup_args *args) {
|
cleanup_task(cleanup_args *args) {
|
||||||
spawn_args *a = args->spargs;
|
spawn_args *a = args->spargs;
|
||||||
bool failed = args->failed;
|
bool threw_exception = args->threw_exception;
|
||||||
rust_task *task = a->task;
|
rust_task *task = a->task;
|
||||||
|
|
||||||
cc::do_cc(task);
|
cc::do_cc(task);
|
||||||
|
|
||||||
task->die();
|
task->die();
|
||||||
|
|
||||||
if (task->killed && !failed) {
|
if (task->killed && !threw_exception) {
|
||||||
LOG(task, task, "Task killed during termination");
|
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__
|
#ifndef __WIN32__
|
||||||
task->conclude_failure();
|
task->conclude_failure();
|
||||||
#else
|
#else
|
||||||
|
@ -336,7 +336,7 @@ void task_start_wrapper(spawn_args *a)
|
||||||
{
|
{
|
||||||
rust_task *task = a->task;
|
rust_task *task = a->task;
|
||||||
|
|
||||||
bool failed = false;
|
bool threw_exception = false;
|
||||||
try {
|
try {
|
||||||
// The first argument is the return pointer; as the task fn
|
// The first argument is the return pointer; as the task fn
|
||||||
// must have void return type, we can safely pass 0.
|
// 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) {
|
} catch (rust_task *ex) {
|
||||||
A(task->sched, ex == task,
|
A(task->sched, ex == task,
|
||||||
"Expected this task to be thrown for unwinding");
|
"Expected this task to be thrown for unwinding");
|
||||||
failed = true;
|
threw_exception = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rust_opaque_closure* env = a->envptr;
|
rust_opaque_closure* env = a->envptr;
|
||||||
|
@ -357,7 +357,7 @@ void task_start_wrapper(spawn_args *a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The cleanup work needs lots of stack
|
// 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->sched->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task);
|
||||||
|
|
||||||
task->ctx.next->swap(task->ctx);
|
task->ctx.next->swap(task->ctx);
|
||||||
|
@ -437,11 +437,17 @@ rust_task::kill() {
|
||||||
// run_on_resume(rust_unwind_glue);
|
// run_on_resume(rust_unwind_glue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL
|
||||||
|
bool rust_task_is_unwinding(rust_task *rt) {
|
||||||
|
return rt->unwinding;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rust_task::fail() {
|
rust_task::fail() {
|
||||||
// See note in ::kill() regarding who should call this.
|
// See note in ::kill() regarding who should call this.
|
||||||
DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this);
|
DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this);
|
||||||
backtrace();
|
backtrace();
|
||||||
|
unwinding = true;
|
||||||
#ifndef __WIN32__
|
#ifndef __WIN32__
|
||||||
throw this;
|
throw this;
|
||||||
#else
|
#else
|
||||||
|
@ -455,7 +461,6 @@ rust_task::fail() {
|
||||||
void
|
void
|
||||||
rust_task::conclude_failure() {
|
rust_task::conclude_failure() {
|
||||||
fail_parent();
|
fail_parent();
|
||||||
failed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -107,8 +107,10 @@ rust_task : public kernel_owned<rust_task>, rust_cond
|
||||||
|
|
||||||
memory_region local_region;
|
memory_region local_region;
|
||||||
|
|
||||||
// Indicates that the task ended in failure
|
// Indicates that fail() has been called and we are cleaning up.
|
||||||
bool failed;
|
// We use this to suppress the "killed" flag during calls to yield.
|
||||||
|
bool unwinding;
|
||||||
|
|
||||||
// Indicates that the task was killed and needs to unwind
|
// Indicates that the task was killed and needs to unwind
|
||||||
bool killed;
|
bool killed;
|
||||||
bool propagate_failure;
|
bool propagate_failure;
|
||||||
|
|
|
@ -43,6 +43,7 @@ rust_ptr_eq
|
||||||
rust_run_program
|
rust_run_program
|
||||||
rust_start
|
rust_start
|
||||||
rust_getcwd
|
rust_getcwd
|
||||||
|
rust_task_is_unwinding
|
||||||
rust_task_sleep
|
rust_task_sleep
|
||||||
rust_get_task
|
rust_get_task
|
||||||
set_min_stack
|
set_min_stack
|
||||||
|
|
|
@ -10,18 +10,26 @@ fn joinable(f: fn()) -> (task::task, comm::port<bool>) {
|
||||||
resource notify(data: (comm::chan<bool>,
|
resource notify(data: (comm::chan<bool>,
|
||||||
@mutable bool)) {
|
@mutable bool)) {
|
||||||
let (c, v) = data;
|
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);
|
comm::send(c, *v);
|
||||||
}
|
}
|
||||||
fn wrapper(pair: (comm::chan<bool>, fn())) {
|
fn wrapper(pair: (comm::chan<bool>, fn())) {
|
||||||
let (c, f) = pair;
|
let (c, f) = pair;
|
||||||
let b = @mutable false;
|
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));
|
let _r = notify((c, b));
|
||||||
f();
|
f();
|
||||||
*b = true;
|
*b = true;
|
||||||
}
|
}
|
||||||
let p = comm::port();
|
let p = comm::port();
|
||||||
let c = comm::chan(p);
|
let c = comm::chan(p);
|
||||||
let t = task::spawn((c, f), wrapper);
|
let t = task::spawn {|| wrapper((c, f)) };
|
||||||
ret (t, p);
|
ret (t, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +42,7 @@ fn supervised() {
|
||||||
// Yield to make sure the supervisor joins before we
|
// Yield to make sure the supervisor joins before we
|
||||||
// fail. This is currently not needed because the supervisor
|
// fail. This is currently not needed because the supervisor
|
||||||
// runs first, but I can imagine that changing.
|
// runs first, but I can imagine that changing.
|
||||||
|
#error["supervised task=%d", task::get_task()];
|
||||||
task::yield();
|
task::yield();
|
||||||
fail;
|
fail;
|
||||||
}
|
}
|
||||||
|
@ -42,8 +51,9 @@ fn supervisor() {
|
||||||
// Unsupervise this task so the process doesn't return a failure status as
|
// Unsupervise this task so the process doesn't return a failure status as
|
||||||
// a result of the main task being killed.
|
// a result of the main task being killed.
|
||||||
task::unsupervise();
|
task::unsupervise();
|
||||||
let f = supervised;
|
#error["supervisor task=%d", task::get_task()];
|
||||||
join(joinable(supervised));
|
let t = joinable(supervised);
|
||||||
|
join(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue