Skip to content

Commit 7277cd7

Browse files
committed
core: Add task::unkillable
1 parent 8fe0461 commit 7277cd7

File tree

5 files changed

+92
-2
lines changed

5 files changed

+92
-2
lines changed

src/libcore/task.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export try;
5151
export yield;
5252
export failing;
5353
export get_task;
54-
54+
export unkillable;
5555

5656
/* Data types */
5757

@@ -467,6 +467,29 @@ fn get_task() -> task {
467467
task(rustrt::get_task_id())
468468
}
469469

470+
#[doc = "
471+
Temporarily make the task unkillable
472+
473+
# Example
474+
475+
task::unkillable {||
476+
// detach / yield / destroy must all be called together
477+
rustrt::rust_port_detach(po);
478+
// This must not result in the current task being killed
479+
task::yield();
480+
rustrt::rust_port_destroy(po);
481+
}
482+
483+
"]
484+
unsafe fn unkillable(f: fn()) {
485+
resource allow_failure(_i: ()) {
486+
rustrt::rust_task_allow_kill();
487+
}
488+
let _allow_failure = allow_failure(());
489+
rustrt::rust_task_inhibit_kill();
490+
f();
491+
}
492+
470493

471494
/* Internal */
472495

@@ -566,6 +589,8 @@ native mod rustrt {
566589
fn rust_task_is_unwinding(rt: *rust_task) -> bool;
567590
fn unsupervise();
568591
fn rust_osmain_sched_id() -> sched_id;
592+
fn rust_task_inhibit_kill();
593+
fn rust_task_allow_kill();
569594
}
570595

571596

@@ -930,3 +955,39 @@ fn test_osmain() {
930955
}
931956
comm::recv(po);
932957
}
958+
959+
#[test]
960+
#[ignore(cfg(target_os = "win32"))]
961+
#[should_fail]
962+
fn test_unkillable() unsafe {
963+
import comm::methods;
964+
let po = comm::port();
965+
let ch = po.chan();
966+
967+
// We want to do this after failing
968+
spawn {||
969+
iter::repeat(10u, yield);
970+
ch.send(());
971+
}
972+
973+
spawn {||
974+
yield();
975+
// We want to fail after the unkillable task
976+
// blocks on recv
977+
fail;
978+
}
979+
980+
unkillable {||
981+
let p = ~0;
982+
let pp: *uint = unsafe::reinterpret_cast(p);
983+
unsafe::forget(p);
984+
985+
// If we are killed here then the box will leak
986+
po.recv();
987+
988+
let _p: ~int = unsafe::reinterpret_cast(pp);
989+
}
990+
991+
// Now we can be killed
992+
po.recv();
993+
}

src/rt/rust_builtin.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,18 @@ rust_global_env_chan_ptr() {
805805
return task->kernel->get_global_env_chan();
806806
}
807807

808+
extern "C" void
809+
rust_task_inhibit_kill() {
810+
rust_task *task = rust_get_current_task();
811+
task->inhibit_kill();
812+
}
813+
814+
extern "C" void
815+
rust_task_allow_kill() {
816+
rust_task *task = rust_get_current_task();
817+
task->allow_kill();
818+
}
819+
808820
//
809821
// Local Variables:
810822
// mode: C++

src/rt/rust_task.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
3737
cond_name("none"),
3838
killed(false),
3939
reentered_rust_stack(false),
40+
disallow_kill(false),
4041
c_stack(NULL),
4142
next_c_sp(0),
4243
next_rust_sp(0),
@@ -211,7 +212,7 @@ rust_task::must_fail_from_being_killed() {
211212
bool
212213
rust_task::must_fail_from_being_killed_unlocked() {
213214
kill_lock.must_have_lock();
214-
return killed && !reentered_rust_stack;
215+
return killed && !reentered_rust_stack && !disallow_kill;
215216
}
216217

217218
// Only run this on the rust stack
@@ -645,6 +646,16 @@ rust_task::on_rust_stack() {
645646
}
646647
}
647648

649+
void
650+
rust_task::inhibit_kill() {
651+
disallow_kill = true;
652+
}
653+
654+
void
655+
rust_task::allow_kill() {
656+
disallow_kill = false;
657+
}
658+
648659
//
649660
// Local Variables:
650661
// mode: C++

src/rt/rust_task.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
155155
bool killed;
156156
// Indicates that we've called back into Rust from C
157157
bool reentered_rust_stack;
158+
bool disallow_kill;
158159

159160
// The stack used for running C code, borrowed from the scheduler thread
160161
stk_seg *c_stack;
@@ -268,6 +269,9 @@ rust_task : public kernel_owned<rust_task>, rust_cond
268269
const char *get_cond_name() { return cond_name; }
269270

270271
void cleanup_after_turn();
272+
273+
void inhibit_kill();
274+
void allow_kill();
271275
};
272276

273277
// FIXME: It would be really nice to be able to get rid of this.

src/rt/rustrt.def.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,5 @@ rust_global_env_chan_ptr
152152
rust_port_take
153153
rust_port_drop
154154
rust_port_task
155+
rust_task_inhibit_kill
156+
rust_task_allow_kill

0 commit comments

Comments
 (0)