diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-06-03 18:58:26 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-06-05 21:38:58 -0700 |
| commit | f7e242ab8a4ceffd87ec339086b7f8510e94aef1 (patch) | |
| tree | 0da571ab3a82f5e947f7660b19c0c4d796a8dba6 /src/libstd/rt | |
| parent | 2e6d51f9cea14ff271223855454034b27ced4ce9 (diff) | |
| download | rust-f7e242ab8a4ceffd87ec339086b7f8510e94aef1.tar.gz rust-f7e242ab8a4ceffd87ec339086b7f8510e94aef1.zip | |
std::rt: Destroy the task start closure while in task context
Diffstat (limited to 'src/libstd/rt')
| -rw-r--r-- | src/libstd/rt/sched.rs | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index b0080a01014..1d1c3aae1f1 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -536,6 +536,7 @@ pub impl Coroutine { priv fn build_start_wrapper(start: ~fn()) -> ~fn() { // XXX: The old code didn't have this extra allocation + let start_cell = Cell(start); let wrapper: ~fn() = || { // This is the first code to execute after the initial // context switch to the task. The previous context may @@ -547,7 +548,19 @@ pub impl Coroutine { let sched = Local::unsafe_borrow::<Scheduler>(); let task = (*sched).current_task.get_mut_ref(); // FIXME #6141: shouldn't neet to put `start()` in another closure - task.task.run(||start()); + let start_cell = Cell(start_cell.take()); + do task.task.run { + // N.B. Removing `start` from the start wrapper closure + // by emptying a cell is critical for correctness. The ~Task + // pointer, and in turn the closure used to initialize the first + // call frame, is destroyed in scheduler context, not task context. + // So any captured closures must not contain user-definable dtors + // that expect to be in task context. By moving `start` out of + // the closure, all the user code goes out of scope while + // the task is still running. + let start = start_cell.take(); + start(); + }; } let sched = Local::take::<Scheduler>(); @@ -840,4 +853,26 @@ mod test { } + #[test] + fn start_closure_dtor() { + use ops::Drop; + + // Regression test that the `start` task entrypoint can contain dtors + // that use task resources + do run_in_newsched_task { + struct S { field: () } + + impl Drop for S { + fn finalize(&self) { + let _foo = @0; + } + } + + let s = S { field: () }; + + do spawntask { + let _ss = &s; + } + } + } } |
