rt: Don't swatch stacks during upcall_del_stack

This commit is contained in:
Brian Anderson
2012-03-21 00:31:40 -07:00
parent 9ba712fb8b
commit 8a145a601e
4 changed files with 43 additions and 52 deletions

View File

@@ -520,17 +520,20 @@ rust_task::new_stack(size_t requested_sz) {
size_t min_sz = thread->min_stack_size;
// Try to reuse an existing stack segment
if (stk != NULL && stk->prev != NULL) {
while (stk != NULL && stk->prev != NULL) {
size_t prev_sz = user_stack_size(stk->prev);
if (min_sz <= prev_sz && requested_sz <= prev_sz) {
LOG(this, mem, "reusing existing stack");
stk = stk->prev;
A(thread, stk->prev == NULL, "Bogus stack ptr");
return;
} else {
LOG(this, mem, "existing stack is not big enough");
stk_seg *new_prev = stk->prev->prev;
free_stack(stk->prev);
stk->prev = NULL;
stk->prev = new_prev;
if (new_prev) {
new_prev->next = stk;
}
}
}
@@ -553,42 +556,15 @@ rust_task::new_stack(size_t requested_sz) {
LOGPTR(thread, "new stk", (uintptr_t)new_stk);
new_stk->prev = NULL;
new_stk->next = stk;
if (stk) {
stk->prev = new_stk;
}
LOGPTR(thread, "stk end", new_stk->end);
stk = new_stk;
total_stack_sz += user_stack_size(new_stk);
}
void
rust_task::del_stack() {
stk_seg *old_stk = stk;
::check_stack_canary(old_stk);
stk = old_stk->next;
bool delete_stack = false;
if (stk != NULL) {
// Don't actually delete this stack. Save it to reuse later,
// preventing the pathological case where we repeatedly reallocate
// the stack for the next frame.
stk->prev = old_stk;
} else {
// This is the last stack, delete it.
delete_stack = true;
}
// Delete the previous previous stack
if (old_stk->prev != NULL) {
free_stack(old_stk->prev);
old_stk->prev = NULL;
}
if (delete_stack) {
free_stack(old_stk);
A(thread, total_stack_sz == 0, "Stack size should be 0");
}
}
void *
rust_task::next_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
stk_seg *maybe_next_stack = NULL;
@@ -615,17 +591,18 @@ rust_task::next_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
}
memcpy(new_sp, args_addr, args_sz);
A(thread, rust_task_thread::get_task() == this,
"Recording the stack limit for the wrong thread");
record_stack_limit();
return new_sp;
}
// NB: This runs on the Rust stack
void
rust_task::prev_stack() {
del_stack();
A(thread, rust_task_thread::get_task() == this,
"Recording the stack limit for the wrong thread");
// We're not going to actually delete anything now because that would
// require switching to the C stack and be costly. Instead we'll just move
// up the link list and clean up later, either in new_stack or after our
// turn ends on the scheduler.
stk = stk->next;
record_stack_limit();
}
@@ -645,6 +622,18 @@ rust_task::record_stack_limit() {
record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE);
}
void
rust_task::cleanup_after_turn() {
// Delete any spare stack segments that were left
// behind by calls to prev_stack
I(thread, stk);
while (stk->prev) {
stk_seg *new_prev = stk->prev->prev;
free_stack(stk->prev);
stk->prev = new_prev;
}
}
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
@@ -666,7 +655,7 @@ reset_stack_limit_on_c_stack(reset_args *args) {
rust_task *task = args->task;
uintptr_t sp = args->sp;
while (!sp_in_stk_seg(sp, task->stk)) {
task->del_stack();
task->stk = task->stk->next;
A(task->thread, task->stk != NULL,
"Failed to find the current stack");
}
@@ -674,10 +663,9 @@ reset_stack_limit_on_c_stack(reset_args *args) {
}
/*
Called by landing pads during unwinding to figure out which
stack segment we are currently running on, delete the others,
and record the stack limit (which was not restored when unwinding
through __morestack).
Called by landing pads during unwinding to figure out which stack segment we
are currently running on and record the stack limit (which was not restored
when unwinding through __morestack).
*/
void
rust_task::reset_stack_limit() {
@@ -685,6 +673,8 @@ rust_task::reset_stack_limit() {
uintptr_t sp = get_sp();
// Have to do the rest on the C stack because it involves
// freeing stack segments, logging, etc.
// FIXME: This probably doesn't need to happen on the C
// stack now
reset_args ra = {this, sp};
call_on_c_stack(&ra, (void*)reset_stack_limit_on_c_stack);
}
@@ -699,8 +689,11 @@ rust_task::delete_all_stacks() {
I(thread, !on_rust_stack());
// Delete all the stacks. There may be more than one if the task failed
// and no landing pads stopped to clean up.
I(thread, stk->prev == NULL);
while (stk != NULL) {
del_stack();
stk_seg *next = stk->next;
free_stack(stk);
stk = next;
}
}