rt: Don't kill tasks while they are in a callback from C
This commit is contained in:
parent
3f4872f032
commit
d5e7f0d113
4 changed files with 56 additions and 6 deletions
|
@ -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
|
// If this task has been killed then we're not going to bother
|
||||||
// blocking, we have to unwind.
|
// blocking, we have to unwind.
|
||||||
if (task->killed) {
|
if (task->must_fail_from_being_killed()) {
|
||||||
*killed = true;
|
*killed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,11 +84,12 @@ rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
|
||||||
local_region(&thread->srv->local_region),
|
local_region(&thread->srv->local_region),
|
||||||
boxed(&local_region),
|
boxed(&local_region),
|
||||||
unwinding(false),
|
unwinding(false),
|
||||||
killed(false),
|
|
||||||
propagate_failure(true),
|
propagate_failure(true),
|
||||||
dynastack(this),
|
dynastack(this),
|
||||||
cc_counter(0),
|
cc_counter(0),
|
||||||
total_stack_sz(0),
|
total_stack_sz(0),
|
||||||
|
killed(false),
|
||||||
|
reentered_rust_stack(false),
|
||||||
c_stack(NULL),
|
c_stack(NULL),
|
||||||
next_c_sp(0),
|
next_c_sp(0),
|
||||||
next_rust_sp(0)
|
next_rust_sp(0)
|
||||||
|
@ -240,17 +241,22 @@ void rust_task::start()
|
||||||
transition(&thread->newborn_tasks, &thread->running_tasks);
|
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
|
// Only run this on the rust stack
|
||||||
void
|
void
|
||||||
rust_task::yield(bool *killed) {
|
rust_task::yield(bool *killed) {
|
||||||
if (this->killed) {
|
if (must_fail_from_being_killed()) {
|
||||||
*killed = true;
|
*killed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return to the scheduler.
|
// Return to the scheduler.
|
||||||
ctx.next->swap(ctx);
|
ctx.next->swap(ctx);
|
||||||
|
|
||||||
if (this->killed) {
|
if (must_fail_from_being_killed()) {
|
||||||
*killed = true;
|
*killed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ typedef unsigned long task_result;
|
||||||
#define tr_failure 1
|
#define tr_failure 1
|
||||||
|
|
||||||
struct spawn_args;
|
struct spawn_args;
|
||||||
|
struct cleanup_args;
|
||||||
|
|
||||||
// std::lib::task::task_notification
|
// 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.
|
// We use this to suppress the "killed" flag during calls to yield.
|
||||||
bool unwinding;
|
bool unwinding;
|
||||||
|
|
||||||
// Indicates that the task was killed and needs to unwind
|
|
||||||
bool killed;
|
|
||||||
bool propagate_failure;
|
bool propagate_failure;
|
||||||
|
|
||||||
lock_and_signal lock;
|
lock_and_signal lock;
|
||||||
|
@ -107,6 +106,11 @@ rust_task : public kernel_owned<rust_task>, rust_cond
|
||||||
|
|
||||||
private:
|
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
|
// The stack used for running C code, borrowed from the scheduler thread
|
||||||
stk_seg *c_stack;
|
stk_seg *c_stack;
|
||||||
uintptr_t next_c_sp;
|
uintptr_t next_c_sp;
|
||||||
|
@ -123,6 +127,7 @@ private:
|
||||||
void return_c_stack();
|
void return_c_stack();
|
||||||
|
|
||||||
friend void task_start_wrapper(spawn_args *a);
|
friend void task_start_wrapper(spawn_args *a);
|
||||||
|
friend void cleanup_task(cleanup_args *a);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -162,6 +167,10 @@ public:
|
||||||
// Fail this task (assuming caller-on-stack is different task).
|
// Fail this task (assuming caller-on-stack is different task).
|
||||||
void kill();
|
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.
|
// Fail self, assuming caller-on-stack is this task.
|
||||||
void fail();
|
void fail();
|
||||||
void conclude_failure();
|
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, !on_rust_stack());
|
||||||
I(thread, next_rust_sp);
|
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;
|
uintptr_t prev_c_sp = next_c_sp;
|
||||||
next_c_sp = get_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);
|
__morestack(args, fn_ptr, sp);
|
||||||
|
|
||||||
next_c_sp = prev_c_sp;
|
next_c_sp = prev_c_sp;
|
||||||
|
reentered_rust_stack = had_reentered_rust_stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
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…
Add table
Add a link
Reference in a new issue