about summary refs log tree commit diff
path: root/src/rt
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-03-21 14:15:30 -0700
committerBrian Anderson <banderson@mozilla.com>2012-03-21 19:10:32 -0700
commit4ad57f5c39e9723fe2a4611d3b5987ad113be695 (patch)
treea5b421cf92866f6888cd896e36a17c12b9eaef3a /src/rt
parent08f783ff10cd561fbe31d5744fd42713d4b3764f (diff)
downloadrust-4ad57f5c39e9723fe2a4611d3b5987ad113be695.tar.gz
rust-4ad57f5c39e9723fe2a4611d3b5987ad113be695.zip
rt: Add rust_task::get_task_from_tcb
Diffstat (limited to 'src/rt')
-rw-r--r--src/rt/rust_task.h41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index 8ffc9c8c1db..a5a33013eea 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -61,6 +61,18 @@
 #endif
 #endif
 
+extern "C" CDECL void
+record_sp_limit(void *limit);
+extern "C" CDECL uintptr_t
+get_sp_limit();
+
+// The function prolog compares the amount of stack needed to the end of
+// the stack. As an optimization, when the frame size is less than 256
+// bytes, it will simply compare %esp to to the stack limit instead of
+// subtracting the frame size. As a result we need our stack limit to
+// account for those 256 bytes.
+const unsigned LIMIT_OFFSET = 256;
+
 struct rust_box;
 
 struct frame_glue_fns {
@@ -257,6 +269,7 @@ public:
     const char *get_cond_name() { return cond_name; }
 
     void cleanup_after_turn();
+    static rust_task *get_task_from_tcb();
 };
 
 // This stuff is on the stack-switching fast path
@@ -432,12 +445,6 @@ record_sp_limit(void *limit);
 inline void
 rust_task::record_stack_limit() {
     I(thread, stk);
-    // The function prolog compares the amount of stack needed to the end of
-    // the stack. As an optimization, when the frame size is less than 256
-    // bytes, it will simply compare %esp to to the stack limit instead of
-    // subtracting the frame size. As a result we need our stack limit to
-    // account for those 256 bytes.
-    const unsigned LIMIT_OFFSET = 256;
     A(thread,
       (uintptr_t)stk->end - RED_ZONE_SIZE
       - (uintptr_t)stk->data >= LIMIT_OFFSET,
@@ -445,6 +452,28 @@ rust_task::record_stack_limit() {
     record_sp_limit(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE);
 }
 
+// The stack pointer boundary is stored in a quickly-accessible location
+// in the TCB. From that we can calculate the address of the stack segment
+// structure it belongs to, and in that structure is a pointer to the task
+// that owns it.
+inline rust_task*
+rust_task::get_task_from_tcb() {
+    uintptr_t sp_limit = get_sp_limit();
+    // FIXME (1226) - Because of a hack in upcall_call_shim_on_c_stack this
+    // value is sometimes inconveniently set to 0, so we can't use this
+    // method of retreiving the task pointer and need to fall back to TLS.
+    if (sp_limit == 0) {
+        return NULL;
+    }
+
+    uintptr_t seg_addr =
+        sp_limit - RED_ZONE_SIZE - LIMIT_OFFSET - sizeof(stk_seg);
+    stk_seg *stk = (stk_seg*) seg_addr;
+    // Make sure we've calculated the right address
+    ::check_stack_canary(stk);
+    assert(stk->task != NULL && "task pointer not in stack structure");
+    return stk->task;
+}
 
 //
 // Local Variables: