rt: Don't kill tasks while they are in a callback from C

This commit is contained in:
Brian Anderson 2012-02-14 00:43:45 -08:00
parent 3f4872f032
commit d5e7f0d113
4 changed files with 56 additions and 6 deletions

View File

@ -576,7 +576,7 @@ port_recv(uintptr_t *dptr, rust_port *port,
// If this task has been killed then we're not going to bother
// blocking, we have to unwind.
if (task->killed) {
if (task->must_fail_from_being_killed()) {
*killed = true;
return;
}

View File

@ -84,11 +84,12 @@ rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
local_region(&thread->srv->local_region),
boxed(&local_region),
unwinding(false),
killed(false),
propagate_failure(true),
dynastack(this),
cc_counter(0),
total_stack_sz(0),
killed(false),
reentered_rust_stack(false),
c_stack(NULL),
next_c_sp(0),
next_rust_sp(0)
@ -240,17 +241,22 @@ void rust_task::start()
transition(&thread->newborn_tasks, &thread->running_tasks);
}
bool
rust_task::must_fail_from_being_killed() {
return killed && !reentered_rust_stack;
}
// Only run this on the rust stack
void
rust_task::yield(bool *killed) {
if (this->killed) {
if (must_fail_from_being_killed()) {
*killed = true;
}
// Return to the scheduler.
ctx.next->swap(ctx);
if (this->killed) {
if (must_fail_from_being_killed()) {
*killed = true;
}
}

View File

@ -37,6 +37,7 @@ typedef unsigned long task_result;
#define tr_failure 1
struct spawn_args;
struct cleanup_args;
// std::lib::task::task_notification
//
@ -88,8 +89,6 @@ rust_task : public kernel_owned<rust_task>, rust_cond
// 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;
lock_and_signal lock;
@ -107,6 +106,11 @@ rust_task : public kernel_owned<rust_task>, rust_cond
private:
// Indicates that the task was killed and needs to unwind
bool killed;
// Indicates that we've called back into Rust from C
bool reentered_rust_stack;
// The stack used for running C code, borrowed from the scheduler thread
stk_seg *c_stack;
uintptr_t next_c_sp;
@ -123,6 +127,7 @@ private:
void return_c_stack();
friend void task_start_wrapper(spawn_args *a);
friend void cleanup_task(cleanup_args *a);
public:
@ -162,6 +167,10 @@ public:
// Fail this task (assuming caller-on-stack is different task).
void kill();
// Indicates that we've been killed and now is an apropriate
// time to fail as a result
bool must_fail_from_being_killed();
// Fail self, assuming caller-on-stack is this task.
void fail();
void conclude_failure();
@ -262,6 +271,9 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
// I(thread, !on_rust_stack());
I(thread, next_rust_sp);
bool had_reentered_rust_stack = reentered_rust_stack;
reentered_rust_stack = true;
uintptr_t prev_c_sp = next_c_sp;
next_c_sp = get_sp();
@ -270,6 +282,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
__morestack(args, fn_ptr, sp);
next_c_sp = prev_c_sp;
reentered_rust_stack = had_reentered_rust_stack;
}
inline void

View File

@ -0,0 +1,31 @@
// error-pattern:explicit failure
// Testing that runtime failure doesn't cause callbacks to abort abnormally.
// Instead the failure will be delivered after the callbacks return.
native mod rustrt {
fn rust_dbg_call(cb: *u8,
data: ctypes::uintptr_t) -> ctypes::uintptr_t;
}
crust fn cb(data: ctypes::uintptr_t) -> ctypes::uintptr_t {
if data == 1u {
data
} else {
count(data - 1u) + count(data - 1u)
}
}
fn count(n: uint) -> uint {
task::yield();
rustrt::rust_dbg_call(cb, n)
}
fn main() {
iter::repeat(10u) {||
task::spawn {||
let result = count(5u);
#debug("result = %?", result);
fail;
};
}
}