Guarantee that native tasks wait for children

There was a scheduling race where a child may not increment the global task
count before the parent exits, and the parent would then think that there are no
more tasks left.
This commit is contained in:
Alex Crichton 2014-01-04 12:02:02 -08:00
parent b432e82515
commit 9c8813f006
2 changed files with 33 additions and 1 deletions

View File

@ -72,6 +72,11 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) {
let task = task;
let ops = ops();
// Note that this increment must happen *before* the spawn in order to
// guarantee that if this task exits it will always end up waiting for the
// spawned task to exit.
bookeeping::increment();
// Spawning a new OS thread guarantees that __morestack will never get
// triggered, but we must manually set up the actual stack bounds once this
// function starts executing. This raises the lower limit by a bit because
@ -88,7 +93,6 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) {
let mut ops = ops;
ops.stack_bounds = Some((my_stack - stack + 1024, my_stack));
bookeeping::increment();
let mut f = Some(f);
let mut task = task;
task.put_runtime(ops as ~rt::Runtime);

View File

@ -0,0 +1,28 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-fast
extern mod native;
static mut set: bool = false;
#[start]
fn start(argc: int, argv: **u8) -> int {
// make sure that native::start always waits for all children to finish
do native::start(argc, argv) {
do spawn {
unsafe { set = true; }
}
};
// if we didn't set the global, then return a nonzero code
if unsafe {set} {0} else {1}
}