diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index 3d3b41338405..12d7b7556978 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -442,15 +442,30 @@ impl Runtime for GreenTask { f: proc():Send) { self.put_task(cur_task); + // First, set up a bomb which when it goes off will restore the local + // task unless its disarmed. This will allow us to gracefully fail from + // inside of `configure` which allocates a new task. + struct Bomb { inner: Option> } + impl Drop for Bomb { + fn drop(&mut self) { + let _ = self.inner.take().map(|task| task.put()); + } + } + let mut bomb = Bomb { inner: Some(self) }; + // Spawns a task into the current scheduler. We allocate the new task's // stack from the scheduler's stack pool, and then configure it // accordingly to `opts`. Afterwards we bootstrap it immediately by // switching to it. // // Upon returning, our task is back in TLS and we're good to return. - let mut sched = self.sched.take_unwrap(); - let sibling = GreenTask::configure(&mut sched.stack_pool, opts, f); - sched.run_task(self, sibling) + let sibling = { + let sched = bomb.inner.get_mut_ref().sched.get_mut_ref(); + GreenTask::configure(&mut sched.stack_pool, opts, f) + }; + let mut me = bomb.inner.take().unwrap(); + let sched = me.sched.take().unwrap(); + sched.run_task(me, sibling) } // Local I/O is provided by the scheduler's event loop diff --git a/src/librustrt/bookkeeping.rs b/src/librustrt/bookkeeping.rs index ba9995e34ca3..dc96aecff801 100644 --- a/src/librustrt/bookkeeping.rs +++ b/src/librustrt/bookkeeping.rs @@ -26,7 +26,7 @@ use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; -pub struct Token(()); +pub struct Token { _private: () } impl Drop for Token { fn drop(&mut self) { decrement() } @@ -36,7 +36,7 @@ impl Drop for Token { /// the count when dropped. pub fn increment() -> Token { let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) }; - Token(()) + Token { _private: () } } pub fn decrement() { diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 0f4d72c9b326..e3d9b7d136ec 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -663,6 +663,6 @@ mod test { fn block_and_wake() { let task = box Task::new(); let mut task = BlockedTask::block(task).wake().unwrap(); - task.destroy(); + task.drop(); } } diff --git a/src/test/run-pass/spawn-stack-too-big.rs b/src/test/run-pass/spawn-stack-too-big.rs new file mode 100644 index 000000000000..e1c4a480d1cc --- /dev/null +++ b/src/test/run-pass/spawn-stack-too-big.rs @@ -0,0 +1,47 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-macos apparently gargantuan mmap requests are ok? + +#![feature(phase)] + +#[phase(plugin)] +extern crate green; +extern crate native; + +use std::task::TaskBuilder; +use native::NativeTaskBuilder; + +green_start!(main) + +fn main() { + test(); + + let (tx, rx) = channel(); + TaskBuilder::new().native().spawn(proc() { + tx.send(test()); + }); + rx.recv(); +} + +#[cfg(not(target_word_size = "64"))] +fn test() {} + +#[cfg(target_word_size = "64")] +fn test() { + let (tx, rx) = channel(); + spawn(proc() { + TaskBuilder::new().stack_size(1024 * 1024 * 1024 * 64).spawn(proc() { + }); + tx.send(()); + }); + + assert!(rx.recv_opt().is_err()); +}