void rust_task::new_stack(size_t requested_sz) { LOG(this, mem, "creating new stack for task %" PRIxPTR, this); if (stk) { ::check_stack_canary(stk); } // The minimum stack size, in bytes, of a Rust stack, excluding red zone size_t min_sz = thread->min_stack_size; // Try to reuse an existing stack segment while (stk != NULL && stk->next != NULL) { size_t next_sz = user_stack_size(stk->next); if (min_sz <= next_sz && requested_sz <= next_sz) { LOG(this, mem, "reusing existing stack"); stk = stk->next; return; } else { LOG(this, mem, "existing stack is not big enough"); stk_seg *new_next = stk->next->next; free_stack(stk->next); stk->next = new_next; if (new_next) { new_next->prev = stk; } } } // The size of the current stack segment, excluding red zone size_t current_sz = 0; if (stk != NULL) { current_sz = user_stack_size(stk); } // The calculated size of the new stack, excluding red zone size_t rust_stk_sz = get_next_stack_size(min_sz, current_sz, requested_sz); if (total_stack_sz + rust_stk_sz > thread->env->max_stack_size) { LOG_ERR(this, task, "task %" PRIxPTR " ran out of stack", this); fail(); } size_t sz = rust_stk_sz + RED_ZONE_SIZE; stk_seg *new_stk = create_stack(&local_region, sz); LOGPTR(thread, "new stk", (uintptr_t)new_stk); new_stk->task = this; new_stk->next = NULL; new_stk->prev = stk; if (stk) { stk->next = new_stk; } LOGPTR(thread, "stk end", new_stk->end); stk = new_stk; total_stack_sz += user_stack_size(new_stk); }
void rust_task::new_stack(size_t requested_sz) { LOG(this, mem, "creating new stack for task %" PRIxPTR, this); if (stk) { ::check_stack_canary(stk); } // The minimum stack size, in bytes, of a Rust stack, excluding red zone size_t min_sz = sched_loop->min_stack_size; // Try to reuse an existing stack segment while (stk != NULL && stk->next != NULL) { size_t next_sz = user_stack_size(stk->next); if (min_sz <= next_sz && requested_sz <= next_sz) { LOG(this, mem, "reusing existing stack"); stk = stk->next; return; } else { LOG(this, mem, "existing stack is not big enough"); stk_seg *new_next = stk->next->next; free_stack(stk->next); stk->next = new_next; if (new_next) { new_next->prev = stk; } } } // The size of the current stack segment, excluding red zone size_t current_sz = 0; if (stk != NULL) { current_sz = user_stack_size(stk); } // The calculated size of the new stack, excluding red zone size_t rust_stk_sz = get_next_stack_size(min_sz, current_sz, requested_sz); size_t max_stack = kernel->env->max_stack_size; size_t used_stack = total_stack_sz + rust_stk_sz; // Don't allow stacks to grow forever. During unwinding we have to allow // for more stack than normal in order to allow destructors room to run, // arbitrarily selected as 2x the maximum stack size. if (!unwinding && used_stack > max_stack) { LOG_ERR(this, task, "task %" PRIxPTR " ran out of stack", this); abort(); } else if (unwinding && used_stack > max_stack * 2) { LOG_ERR(this, task, "task %" PRIxPTR " ran out of stack during unwinding", this); abort(); } size_t sz = rust_stk_sz + RED_ZONE_SIZE; stk_seg *new_stk = create_stack(&local_region, sz); LOGPTR(sched_loop, "new stk", (uintptr_t)new_stk); new_stk->task = this; new_stk->next = NULL; new_stk->prev = stk; if (stk) { stk->next = new_stk; } LOGPTR(sched_loop, "stk end", new_stk->end); stk = new_stk; total_stack_sz += user_stack_size(new_stk); }
void rust_task::free_stack(stk_seg *stk) { LOGPTR(sched_loop, "freeing stk segment", (uintptr_t)stk); total_stack_sz -= user_stack_size(stk); destroy_stack(&local_region, stk); }