diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 4f904ee6e6dd9..ddacc11fd9edd 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -75,6 +75,7 @@ impl Runtime for SimpleTask { fail!() } fn local_io<'a>(&'a mut self) -> Option> { None } + fn stack_bounds(&self) -> Option<(uint, uint)> { None } fn wrap(~self) -> ~Any { fail!() } } diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index fc4e1c08ba5a1..183fe8d055528 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -450,6 +450,13 @@ impl Runtime for GreenTask { } } + fn stack_bounds(&self) -> Option<(uint, uint)> { + self.coroutine.as_ref().map(|c| { + (c.current_stack_segment.start() as uint, + c.current_stack_segment.end() as uint) + }) + } + fn wrap(~self) -> ~Any { self as ~Any } } diff --git a/src/libnative/task.rs b/src/libnative/task.rs index c4d3f65177753..661358a64e98b 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -32,12 +32,17 @@ use bookeeping; /// Creates a new Task which is ready to execute as a 1:1 task. pub fn new() -> ~Task { let mut task = ~Task::new(); - task.put_runtime(~Ops { + task.put_runtime(ops() as ~rt::Runtime); + return task; +} + +fn ops() -> ~Ops { + ~Ops { lock: unsafe { Mutex::new() }, awoken: false, io: io::IoFactory::new(), - } as ~rt::Runtime); - return task; + stack_bounds: None, + } } /// Spawns a function with the default configuration @@ -53,7 +58,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) { notify_chan, name, stack_size } = opts; - let mut task = new(); + let mut task = ~Task::new(); task.name = name; match notify_chan { Some(chan) => { @@ -65,6 +70,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) { let stack = stack_size.unwrap_or(env::min_stack()); let task = task; + let ops = ops(); // Spawning a new OS thread guarantees that __morestack will never get // triggered, but we must manually set up the actual stack bounds once this @@ -75,13 +81,17 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) { Thread::spawn_stack(stack, proc() { let something_around_the_top_of_the_stack = 1; let addr = &something_around_the_top_of_the_stack as *int; + let my_stack = addr as uint; unsafe { - let my_stack = addr as uint; stack::record_stack_bounds(my_stack - stack + 1024, my_stack); } + 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); task.run(|| { f.take_unwrap()() }); bookeeping::decrement(); }) @@ -93,6 +103,11 @@ struct Ops { lock: Mutex, // native synchronization awoken: bool, // used to prevent spurious wakeups io: io::IoFactory, // local I/O factory + + // This field holds the known bounds of the stack in (lo, hi) form. Not all + // native tasks necessarily know their precise bounds, hence this is + // optional. + stack_bounds: Option<(uint, uint)>, } impl rt::Runtime for Ops { @@ -114,6 +129,8 @@ impl rt::Runtime for Ops { self as ~Any } + fn stack_bounds(&self) -> Option<(uint, uint)> { self.stack_bounds } + // This function gets a little interesting. There are a few safety and // ownership violations going on here, but this is all done in the name of // shared state. Additionally, all of the violations are protected with a diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 9bd804f7babe8..050caef86ebdb 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -159,6 +159,7 @@ pub trait Runtime { // you're in. fn spawn_sibling(~self, cur_task: ~Task, opts: TaskOpts, f: proc()); fn local_io<'a>(&'a mut self) -> Option>; + fn stack_bounds(&self) -> Option<(uint, uint)>; // (lo, hi) // XXX: This is a serious code smell and this should not exist at all. fn wrap(~self) -> ~Any; diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 583a1e0657cf8..3fdbc8938ba75 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -277,6 +277,13 @@ impl Task { pub fn local_io<'a>(&'a mut self) -> Option> { self.imp.get_mut_ref().local_io() } + + /// Returns the stack bounds for this task in (lo, hi) format. The stack + /// bounds may not be known for all tasks, so the return value may be + /// `None`. + pub fn stack_bounds(&self) -> Option<(uint, uint)> { + self.imp.get_ref().stack_bounds() + } } impl Drop for Task {