Skip to content

Commit 4cf6b4d

Browse files
committed
Tasks should not hold a ref to their parent (Close #1789)
1 parent d930d71 commit 4cf6b4d

File tree

6 files changed

+24
-58
lines changed

6 files changed

+24
-58
lines changed

src/libcore/sys.rs

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ type rust_cond_lock = *libc::c_void;
1919

2020
#[abi = "cdecl"]
2121
extern mod rustrt {
22-
fn unsupervise();
2322
pure fn shape_log_str(t: *sys::type_desc, data: *()) -> ~str;
2423

2524
fn rust_create_cond_lock() -> rust_cond_lock;

src/libcore/task.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
731731
// Getting killed after here would leak the task.
732732

733733
let child_wrapper =
734-
make_child_wrapper(new_task, child_tg,
735-
opts.supervise, is_main, f);
734+
make_child_wrapper(new_task, child_tg, is_main, f);
736735
let fptr = ptr::addr_of(child_wrapper);
737736
let closure: *rust_closure = unsafe::reinterpret_cast(fptr);
738737

@@ -750,19 +749,14 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
750749
}
751750

752751
fn make_child_wrapper(child_task: *rust_task, -child_tg: taskgroup_arc,
753-
supervise: bool, is_main: bool,
754-
-f: fn~()) -> fn~() {
752+
is_main: bool, -f: fn~()) -> fn~() {
755753
let child_tg_ptr = ~mut some(child_tg);
756754
fn~() {
757755
// Agh. Get move-mode items into the closure. FIXME (#2829)
758756
let mut child_tg_opt = none;
759757
*child_tg_ptr <-> child_tg_opt;
760758
let child_tg = option::unwrap(child_tg_opt);
761759
// Child task runs this code.
762-
if !supervise {
763-
// FIXME (#1868, #1789) take this out later
764-
rustrt::unsupervise();
765-
}
766760
// Set up membership in taskgroup. If this returns none, the
767761
// parent was already failing, so don't bother doing anything.
768762
alt enlist_in_taskgroup(child_tg, child_task) {
@@ -1018,7 +1012,6 @@ extern mod rustrt {
10181012
fn start_task(task: *rust_task, closure: *rust_closure);
10191013

10201014
fn rust_task_is_unwinding(task: *rust_task) -> bool;
1021-
fn unsupervise();
10221015
fn rust_osmain_sched_id() -> sched_id;
10231016
fn rust_task_inhibit_kill();
10241017
fn rust_task_allow_kill();
@@ -1464,6 +1457,21 @@ fn test_unkillable_nested() {
14641457
po.recv();
14651458
}
14661459
1460+
#[test]
1461+
fn test_child_doesnt_ref_parent() {
1462+
// If the child refcounts the parent task, this will stack overflow when
1463+
// climbing the task tree to dereference each ancestor. (See #1789)
1464+
const generations: uint = 8192;
1465+
fn child_no(x: uint) -> fn~() {
1466+
ret || {
1467+
if x < generations {
1468+
task::spawn(child_no(x+1));
1469+
}
1470+
}
1471+
}
1472+
task::spawn(child_no(0));
1473+
}
1474+
14671475
#[test]
14681476
fn test_tls_multitask() unsafe {
14691477
fn my_key(+_x: @~str) { }

src/rt/rust_builtin.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ rust_env_pairs() {
129129

130130
extern "C" CDECL void
131131
unsupervise() {
132-
rust_task *task = rust_get_current_task();
133-
task->unsupervise();
132+
// FIXME(#1789): bblum: remove this; requires a snapshot
134133
}
135134

136135
extern "C" CDECL void

src/rt/rust_sched_loop.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ rust_sched_loop::kill_all_tasks() {
7676
while (!all_tasks.empty()) {
7777
rust_task *task = all_tasks.back();
7878
all_tasks.pop_back();
79-
// We don't want the failure of these tasks to propagate back
80-
// to the kernel again since we're already failing everything
81-
task->unsupervise();
8279
task->kill();
8380
}
8481
}
@@ -261,9 +258,9 @@ rust_sched_loop::create_task(rust_task *spawner, const char *name) {
261258
rust_task *task =
262259
new (this->kernel, "rust_task")
263260
rust_task(this, task_state_newborn,
264-
spawner, name, kernel->env->min_stack_size);
261+
name, kernel->env->min_stack_size);
265262
DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s",
266-
task, spawner ? spawner->name : "null", name);
263+
task, spawner ? spawner->name : "(none)", name);
267264

268265
task->id = kernel->generate_task_id();
269266
return task;

src/rt/rust_task.cpp

+2-34
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
#include "rust_env.h"
1111
#include "rust_port.h"
1212

13-
// FIXME (#1789) (bblum): get rid of supervisors
14-
1513
// Tasks
1614
rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
17-
rust_task *spawner, const char *name,
18-
size_t init_stack_sz) :
15+
const char *name, size_t init_stack_sz) :
1916
ref_count(1),
2017
id(0),
2118
notify_enabled(false),
@@ -30,7 +27,6 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
3027
local_region(&sched_loop->local_region),
3128
boxed(sched_loop->kernel->env, &local_region),
3229
unwinding(false),
33-
propagate_failure(true),
3430
cc_counter(0),
3531
total_stack_sz(0),
3632
task_local_data(NULL),
@@ -45,17 +41,13 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
4541
disallow_kill(0),
4642
c_stack(NULL),
4743
next_c_sp(0),
48-
next_rust_sp(0),
49-
supervisor(spawner)
44+
next_rust_sp(0)
5045
{
5146
LOGPTR(sched_loop, "new task", (uintptr_t)this);
5247
DLOG(sched_loop, task, "sizeof(task) = %d (0x%x)",
5348
sizeof *this, sizeof *this);
5449

5550
new_stack(init_stack_sz);
56-
if (supervisor) {
57-
supervisor->ref();
58-
}
5951
}
6052

6153
// NB: This does not always run on the task's scheduler thread
@@ -65,15 +57,6 @@ rust_task::delete_this()
6557
DLOG(sched_loop, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
6658
name, (uintptr_t)this, ref_count);
6759

68-
// FIXME (#2677): We should do this when the task exits, not in the
69-
// destructor
70-
{
71-
scoped_lock with(supervisor_lock);
72-
if (supervisor) {
73-
supervisor->deref();
74-
}
75-
}
76-
7760
/* FIXME (#2677): tighten this up, there are some more
7861
assertions that hold at task-lifecycle events. */
7962
assert(ref_count == 0); // ||
@@ -335,21 +318,6 @@ void rust_task::fail_sched_loop() {
335318
sched_loop->fail();
336319
}
337320

338-
void
339-
rust_task::unsupervise()
340-
{
341-
scoped_lock with(supervisor_lock);
342-
if (supervisor) {
343-
DLOG(sched_loop, task,
344-
"task %s @0x%" PRIxPTR
345-
" disconnecting from supervisor %s @0x%" PRIxPTR,
346-
name, this, supervisor->name, supervisor);
347-
supervisor->deref();
348-
}
349-
supervisor = NULL;
350-
propagate_failure = false;
351-
}
352-
353321
frame_glue_fns*
354322
rust_task::get_frame_glue_fns(uintptr_t fp) {
355323
fp -= sizeof(uintptr_t);

src/rt/rust_task.h

+2-7
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ rust_task_fail(rust_task *task,
122122
struct
123123
rust_task : public kernel_owned<rust_task>
124124
{
125+
// FIXME(#1789) Refcounting no longer seems needed now that tasks don't
126+
// ref their parents. I'll leave it in just in case... -- bblum
125127
RUST_ATOMIC_REFCOUNT();
126128

127129
rust_task_id id;
@@ -193,9 +195,6 @@ rust_task : public kernel_owned<rust_task>
193195

194196
rust_port_selector port_selector;
195197

196-
lock_and_signal supervisor_lock;
197-
rust_task *supervisor; // Parent-link for failure propagation.
198-
199198
// Called when the atomic refcount reaches zero
200199
void delete_this();
201200

@@ -237,7 +236,6 @@ rust_task : public kernel_owned<rust_task>
237236
// Only a pointer to 'name' is kept, so it must live as long as this task.
238237
rust_task(rust_sched_loop *sched_loop,
239238
rust_task_state state,
240-
rust_task *spawner,
241239
const char *name,
242240
size_t init_stack_sz);
243241

@@ -279,9 +277,6 @@ rust_task : public kernel_owned<rust_task>
279277
// FIXME (#1868) (bblum): maybe this can be done at rust-level?
280278
void fail_sched_loop();
281279

282-
// Disconnect from our supervisor.
283-
void unsupervise();
284-
285280
frame_glue_fns *get_frame_glue_fns(uintptr_t fp);
286281

287282
void *calloc(size_t size, const char *tag);

0 commit comments

Comments
 (0)