Skip to content

Commit f7e242a

Browse files
committed
std::rt: Destroy the task start closure while in task context
1 parent 2e6d51f commit f7e242a

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

src/libstd/rt/sched.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ pub impl Coroutine {
536536

537537
priv fn build_start_wrapper(start: ~fn()) -> ~fn() {
538538
// XXX: The old code didn't have this extra allocation
539+
let start_cell = Cell(start);
539540
let wrapper: ~fn() = || {
540541
// This is the first code to execute after the initial
541542
// context switch to the task. The previous context may
@@ -547,7 +548,19 @@ pub impl Coroutine {
547548
let sched = Local::unsafe_borrow::<Scheduler>();
548549
let task = (*sched).current_task.get_mut_ref();
549550
// FIXME #6141: shouldn't neet to put `start()` in another closure
550-
task.task.run(||start());
551+
let start_cell = Cell(start_cell.take());
552+
do task.task.run {
553+
// N.B. Removing `start` from the start wrapper closure
554+
// by emptying a cell is critical for correctness. The ~Task
555+
// pointer, and in turn the closure used to initialize the first
556+
// call frame, is destroyed in scheduler context, not task context.
557+
// So any captured closures must not contain user-definable dtors
558+
// that expect to be in task context. By moving `start` out of
559+
// the closure, all the user code goes out of scope while
560+
// the task is still running.
561+
let start = start_cell.take();
562+
start();
563+
};
551564
}
552565

553566
let sched = Local::take::<Scheduler>();
@@ -840,4 +853,26 @@ mod test {
840853

841854
}
842855

856+
#[test]
857+
fn start_closure_dtor() {
858+
use ops::Drop;
859+
860+
// Regression test that the `start` task entrypoint can contain dtors
861+
// that use task resources
862+
do run_in_newsched_task {
863+
struct S { field: () }
864+
865+
impl Drop for S {
866+
fn finalize(&self) {
867+
let _foo = @0;
868+
}
869+
}
870+
871+
let s = S { field: () };
872+
873+
do spawntask {
874+
let _ss = &s;
875+
}
876+
}
877+
}
843878
}

0 commit comments

Comments
 (0)