Skip to content

Commit d5e7f0d

Browse files
committed
rt: Don't kill tasks while they are in a callback from C
1 parent 3f4872f commit d5e7f0d

File tree

4 files changed

+56
-6
lines changed

4 files changed

+56
-6
lines changed

Diff for: src/rt/rust_builtin.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ port_recv(uintptr_t *dptr, rust_port *port,
576576

577577
// If this task has been killed then we're not going to bother
578578
// blocking, we have to unwind.
579-
if (task->killed) {
579+
if (task->must_fail_from_being_killed()) {
580580
*killed = true;
581581
return;
582582
}

Diff for: src/rt/rust_task.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
8484
local_region(&thread->srv->local_region),
8585
boxed(&local_region),
8686
unwinding(false),
87-
killed(false),
8887
propagate_failure(true),
8988
dynastack(this),
9089
cc_counter(0),
9190
total_stack_sz(0),
91+
killed(false),
92+
reentered_rust_stack(false),
9293
c_stack(NULL),
9394
next_c_sp(0),
9495
next_rust_sp(0)
@@ -240,17 +241,22 @@ void rust_task::start()
240241
transition(&thread->newborn_tasks, &thread->running_tasks);
241242
}
242243

244+
bool
245+
rust_task::must_fail_from_being_killed() {
246+
return killed && !reentered_rust_stack;
247+
}
248+
243249
// Only run this on the rust stack
244250
void
245251
rust_task::yield(bool *killed) {
246-
if (this->killed) {
252+
if (must_fail_from_being_killed()) {
247253
*killed = true;
248254
}
249255

250256
// Return to the scheduler.
251257
ctx.next->swap(ctx);
252258

253-
if (this->killed) {
259+
if (must_fail_from_being_killed()) {
254260
*killed = true;
255261
}
256262
}

Diff for: src/rt/rust_task.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ typedef unsigned long task_result;
3737
#define tr_failure 1
3838

3939
struct spawn_args;
40+
struct cleanup_args;
4041

4142
// std::lib::task::task_notification
4243
//
@@ -88,8 +89,6 @@ rust_task : public kernel_owned<rust_task>, rust_cond
8889
// We use this to suppress the "killed" flag during calls to yield.
8990
bool unwinding;
9091

91-
// Indicates that the task was killed and needs to unwind
92-
bool killed;
9392
bool propagate_failure;
9493

9594
lock_and_signal lock;
@@ -107,6 +106,11 @@ rust_task : public kernel_owned<rust_task>, rust_cond
107106

108107
private:
109108

109+
// Indicates that the task was killed and needs to unwind
110+
bool killed;
111+
// Indicates that we've called back into Rust from C
112+
bool reentered_rust_stack;
113+
110114
// The stack used for running C code, borrowed from the scheduler thread
111115
stk_seg *c_stack;
112116
uintptr_t next_c_sp;
@@ -123,6 +127,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
123127
void return_c_stack();
124128

125129
friend void task_start_wrapper(spawn_args *a);
130+
friend void cleanup_task(cleanup_args *a);
126131

127132
public:
128133

@@ -162,6 +167,10 @@ rust_task : public kernel_owned<rust_task>, rust_cond
162167
// Fail this task (assuming caller-on-stack is different task).
163168
void kill();
164169

170+
// Indicates that we've been killed and now is an apropriate
171+
// time to fail as a result
172+
bool must_fail_from_being_killed();
173+
165174
// Fail self, assuming caller-on-stack is this task.
166175
void fail();
167176
void conclude_failure();
@@ -262,6 +271,9 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
262271
// I(thread, !on_rust_stack());
263272
I(thread, next_rust_sp);
264273

274+
bool had_reentered_rust_stack = reentered_rust_stack;
275+
reentered_rust_stack = true;
276+
265277
uintptr_t prev_c_sp = next_c_sp;
266278
next_c_sp = get_sp();
267279

@@ -270,6 +282,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
270282
__morestack(args, fn_ptr, sp);
271283

272284
next_c_sp = prev_c_sp;
285+
reentered_rust_stack = had_reentered_rust_stack;
273286
}
274287

275288
inline void

Diff for: src/test/run-fail/crust-fail.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// error-pattern:explicit failure
2+
// Testing that runtime failure doesn't cause callbacks to abort abnormally.
3+
// Instead the failure will be delivered after the callbacks return.
4+
5+
native mod rustrt {
6+
fn rust_dbg_call(cb: *u8,
7+
data: ctypes::uintptr_t) -> ctypes::uintptr_t;
8+
}
9+
10+
crust fn cb(data: ctypes::uintptr_t) -> ctypes::uintptr_t {
11+
if data == 1u {
12+
data
13+
} else {
14+
count(data - 1u) + count(data - 1u)
15+
}
16+
}
17+
18+
fn count(n: uint) -> uint {
19+
task::yield();
20+
rustrt::rust_dbg_call(cb, n)
21+
}
22+
23+
fn main() {
24+
iter::repeat(10u) {||
25+
task::spawn {||
26+
let result = count(5u);
27+
#debug("result = %?", result);
28+
fail;
29+
};
30+
}
31+
}

0 commit comments

Comments
 (0)