auto merge of #11306 : alexcrichton/rust/native-bounds, r=pcwalton

This allows inspection of the current task's bounds regardless of what the
underlying task is.

Closes #11293
This commit is contained in:
bors 2014-01-04 10:16:51 -08:00
commit b432e82515
5 changed files with 38 additions and 5 deletions

View File

@ -75,6 +75,7 @@ impl Runtime for SimpleTask {
fail!()
}
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
fn stack_bounds(&self) -> Option<(uint, uint)> { None }
fn wrap(~self) -> ~Any { fail!() }
}

View File

@ -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 }
}

View File

@ -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

View File

@ -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<rtio::LocalIo<'a>>;
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;

View File

@ -277,6 +277,13 @@ impl Task {
pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
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 {