about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-01-04 00:06:13 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-01-04 00:08:03 -0800
commitdcaf10f8de7be79d7ef8aa5e048bf6535108dc16 (patch)
tree2a5a09d84e6db2421076fe36f407f736e989266e
parenta1cb8dc30c6adc88703763a8703b6a3027598b2d (diff)
downloadrust-dcaf10f8de7be79d7ef8aa5e048bf6535108dc16.tar.gz
rust-dcaf10f8de7be79d7ef8aa5e048bf6535108dc16.zip
Add a stack_bounds function to the Runtime trait
This allows inspection of the current task's bounds regardless of what the
underlying task is.

Closes #11293
-rw-r--r--src/libgreen/simple.rs1
-rw-r--r--src/libgreen/task.rs7
-rw-r--r--src/libnative/task.rs27
-rw-r--r--src/libstd/rt/mod.rs1
-rw-r--r--src/libstd/rt/task.rs7
5 files changed, 38 insertions, 5 deletions
diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs
index 4f904ee6e6d..ddacc11fd9e 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<rtio::LocalIo<'a>> { 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 fc4e1c08ba5..183fe8d0555 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 c4d3f651777..661358a64e9 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 9bd804f7bab..050caef86eb 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<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;
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 583a1e0657c..3fdbc8938ba 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<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 {