about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-04-19 19:24:52 -0700
committerbors <bors@rust-lang.org>2013-04-19 19:24:52 -0700
commit8b3c09a1038c6623528fd7ebb1d365e475d63dfc (patch)
treecccb89a294c2efb90a4a319fdd50b0fc0cf6c6e5 /src/rt/rust_task.cpp
parent6510fd92544467a03df93b5124644976aa79f964 (diff)
parentd2b644842a75af44d042f4026a585e4a9cf5979a (diff)
downloadrust-8b3c09a1038c6623528fd7ebb1d365e475d63dfc.tar.gz
rust-8b3c09a1038c6623528fd7ebb1d365e475d63dfc.zip
auto merge of #5962 : pcwalton/rust/shootout, r=pcwalton
r? @brson
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp69
1 files changed, 64 insertions, 5 deletions
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 63dc1c9833e..7e146cce68e 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -53,7 +53,8 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
     disallow_yield(0),
     c_stack(NULL),
     next_c_sp(0),
-    next_rust_sp(0)
+    next_rust_sp(0),
+    big_stack(NULL)
 {
     LOGPTR(sched_loop, "new task", (uintptr_t)this);
     DLOG(sched_loop, task, "sizeof(task) = %d (0x%x)",
@@ -457,8 +458,9 @@ rust_task::get_next_stack_size(size_t min, size_t current, size_t requested) {
         "min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR,
         min, current, requested);
 
-    // Allocate at least enough to accomodate the next frame
-    size_t sz = std::max(min, requested);
+    // Allocate at least enough to accomodate the next frame, plus a little
+    // slack to avoid thrashing
+    size_t sz = std::max(min, requested + (requested / 2));
 
     // And double the stack size each allocation
     const size_t max = 1024 * 1024;
@@ -555,13 +557,63 @@ rust_task::cleanup_after_turn() {
     // Delete any spare stack segments that were left
     // behind by calls to prev_stack
     assert(stk);
+
     while (stk->next) {
         stk_seg *new_next = stk->next->next;
-        free_stack(stk->next);
+
+        if (stk->next->is_big) {
+            assert (big_stack == stk->next);
+            sched_loop->return_big_stack(big_stack);
+            big_stack = NULL;
+        } else {
+            free_stack(stk->next);
+        }
+
         stk->next = new_next;
     }
 }
 
+// NB: Runs on the Rust stack. Returns true if we successfully allocated the big
+// stack and false otherwise.
+bool
+rust_task::new_big_stack() {
+    // If we have a cached big stack segment, use it.
+    if (big_stack) {
+        // Check to see if we're already on the big stack.
+        stk_seg *ss = stk;
+        while (ss != NULL) {
+            if (ss == big_stack)
+                return false;
+            ss = ss->prev;
+        }
+
+        // Unlink the big stack.
+        if (big_stack->next)
+            big_stack->next->prev = big_stack->prev;
+        if (big_stack->prev)
+            big_stack->prev->next = big_stack->next;
+    } else {
+        stk_seg *borrowed_big_stack = sched_loop->borrow_big_stack();
+        if (!borrowed_big_stack) {
+            abort();
+        } else {
+            big_stack = borrowed_big_stack;
+        }
+    }
+
+    big_stack->task = this;
+    big_stack->next = stk->next;
+    if (big_stack->next)
+        big_stack->next->prev = big_stack;
+    big_stack->prev = stk;
+    if (stk)
+        stk->next = big_stack;
+
+    stk = big_stack;
+
+    return true;
+}
+
 static bool
 sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
     // Not positive these bounds for sp are correct.  I think that the first
@@ -601,9 +653,16 @@ rust_task::delete_all_stacks() {
     assert(stk->next == NULL);
     while (stk != NULL) {
         stk_seg *prev = stk->prev;
-        free_stack(stk);
+
+        if (stk->is_big)
+            sched_loop->return_big_stack(stk);
+        else
+            free_stack(stk);
+
         stk = prev;
     }
+
+    big_stack = NULL;
 }
 
 /*