rt: Don't kill tasks while they are in a callback from C
This commit is contained in:
parent
3f4872f032
commit
d5e7f0d113
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
31
src/test/run-fail/crust-fail.rs
Normal file
31
src/test/run-fail/crust-fail.rs
Normal 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;
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user