1
Fork 0

rt: Add RUST_MAX_STACK env var with 8MB default

Closes #1489
This commit is contained in:
Brian Anderson 2012-01-11 12:37:09 -08:00
parent c00ec5f9c9
commit 94c389a25b
9 changed files with 107 additions and 58 deletions

View file

@ -8,6 +8,7 @@
// The environment variables that the runtime knows about // The environment variables that the runtime knows about
#define RUST_THREADS "RUST_THREADS" #define RUST_THREADS "RUST_THREADS"
#define RUST_MIN_STACK "RUST_MIN_STACK" #define RUST_MIN_STACK "RUST_MIN_STACK"
#define RUST_MAX_STACK "RUST_MAX_STACK"
#define RUST_LOG "RUST_LOG" #define RUST_LOG "RUST_LOG"
#define CHECK_CLAIMS "CHECK_CLAIMS" #define CHECK_CLAIMS "CHECK_CLAIMS"
#define DETAILED_LEAKS "DETAILED_LEAKS" #define DETAILED_LEAKS "DETAILED_LEAKS"
@ -69,15 +70,26 @@ get_num_threads()
static size_t static size_t
get_min_stk_size() { get_min_stk_size() {
char *stack_size = getenv(RUST_MIN_STACK); char *minsz = getenv(RUST_MIN_STACK);
if(stack_size) { if(minsz) {
return strtol(stack_size, NULL, 0); return strtol(minsz, NULL, 0);
} }
else { else {
return 0x300; return 0x300;
} }
} }
static size_t
get_max_stk_size() {
char *maxsz = getenv(RUST_MAX_STACK);
if (maxsz) {
return strtol(maxsz, NULL, 0);
}
else {
return 1024*1024*8;
}
}
static char* static char*
copyenv(const char* name) { copyenv(const char* name) {
char *envvar = getenv(name); char *envvar = getenv(name);
@ -99,6 +111,7 @@ load_env() {
env->num_sched_threads = (size_t)get_num_threads(); env->num_sched_threads = (size_t)get_num_threads();
env->min_stack_size = get_min_stk_size(); env->min_stack_size = get_min_stk_size();
env->max_stack_size = get_max_stk_size();
env->logspec = copyenv(RUST_LOG); env->logspec = copyenv(RUST_LOG);
env->check_claims = getenv(CHECK_CLAIMS) != NULL; env->check_claims = getenv(CHECK_CLAIMS) != NULL;
env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL; env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL;

View file

@ -1,6 +1,7 @@
struct rust_env { struct rust_env {
size_t num_sched_threads; size_t num_sched_threads;
size_t min_stack_size; size_t min_stack_size;
size_t max_stack_size;
char* logspec; char* logspec;
bool check_claims; bool check_claims;
bool detailed_leaks; bool detailed_leaks;

View file

@ -121,12 +121,6 @@ unconfig_valgrind_stack(stk_seg *stk) {
VALGRIND_STACK_DEREGISTER(stk->valgrind_id); VALGRIND_STACK_DEREGISTER(stk->valgrind_id);
} }
static void
free_stk(rust_task *task, stk_seg *stk) {
LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
task->free(stk);
}
static void static void
add_stack_canary(stk_seg *stk) { add_stack_canary(stk_seg *stk) {
memcpy(stk->data, stack_canary, sizeof(stack_canary)); memcpy(stk->data, stack_canary, sizeof(stack_canary));
@ -139,6 +133,21 @@ check_stack_canary(stk_seg *stk) {
&& "Somebody killed the canary"); && "Somebody killed the canary");
} }
// The amount of stack in a segment available to Rust code
static size_t
user_stack_size(stk_seg *stk) {
return (size_t)(stk->end
- (uintptr_t)&stk->data[0]
- RED_ZONE_SIZE);
}
static void
free_stk(rust_task *task, stk_seg *stk) {
LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
task->total_stack_sz -= user_stack_size(stk);
task->free(stk);
}
static stk_seg* static stk_seg*
new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz) new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
{ {
@ -152,9 +161,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
// Try to reuse an existing stack segment // Try to reuse an existing stack segment
if (task->stk != NULL && task->stk->prev != NULL) { if (task->stk != NULL && task->stk->prev != NULL) {
size_t prev_sz = (size_t)(task->stk->prev->end size_t prev_sz = user_stack_size(task->stk->prev);
- (uintptr_t)&task->stk->prev->data[0]
- RED_ZONE_SIZE);
if (min_sz <= prev_sz && requested_sz <= prev_sz) { if (min_sz <= prev_sz && requested_sz <= prev_sz) {
LOG(task, mem, "reusing existing stack"); LOG(task, mem, "reusing existing stack");
task->stk = task->stk->prev; task->stk = task->stk->prev;
@ -171,14 +178,17 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
// The size of the current stack segment, excluding red zone // The size of the current stack segment, excluding red zone
size_t current_sz = 0; size_t current_sz = 0;
if (task->stk != NULL) { if (task->stk != NULL) {
current_sz = (size_t)(task->stk->end current_sz = user_stack_size(task->stk);
- (uintptr_t)&task->stk->data[0]
- RED_ZONE_SIZE);
} }
// The calculated size of the new stack, excluding red zone // The calculated size of the new stack, excluding red zone
size_t rust_stk_sz = get_next_stk_size(sched, task, min_sz, size_t rust_stk_sz = get_next_stk_size(sched, task, min_sz,
current_sz, requested_sz); current_sz, requested_sz);
if (task->total_stack_sz + rust_stk_sz > sched->env->max_stack_size) {
LOG_ERR(task, task, "task %" PRIxPTR " ran out of stack", task);
task->fail();
}
size_t sz = sizeof(stk_seg) + rust_stk_sz + RED_ZONE_SIZE; size_t sz = sizeof(stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
stk_seg *stk = (stk_seg *)task->malloc(sz, "stack"); stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
LOGPTR(task->sched, "new stk", (uintptr_t)stk); LOGPTR(task->sched, "new stk", (uintptr_t)stk);
@ -191,6 +201,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
task->stk = stk; task->stk = stk;
config_valgrind_stack(task->stk); config_valgrind_stack(task->stk);
task->total_stack_sz += user_stack_size(stk);
return stk; return stk;
} }
@ -222,6 +233,7 @@ del_stk(rust_task *task, stk_seg *stk)
unconfig_valgrind_stack(stk); unconfig_valgrind_stack(stk);
if (delete_stack) { if (delete_stack) {
free_stk(task, stk); free_stk(task, stk);
A(task->sched, task->total_stack_sz == 0, "Stack size should be 0");
} }
} }
@ -249,7 +261,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
killed(false), killed(false),
propagate_failure(true), propagate_failure(true),
dynastack(this), dynastack(this),
cc_counter(0) cc_counter(0),
total_stack_sz(0)
{ {
LOGPTR(sched, "new task", (uintptr_t)this); LOGPTR(sched, "new task", (uintptr_t)this);
DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this); DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);

View file

@ -126,6 +126,9 @@ rust_task : public kernel_owned<rust_task>, rust_cond
debug::task_debug_info debug; debug::task_debug_info debug;
// The amount of stack we're using, excluding red zones
size_t total_stack_sz;
// Only a pointer to 'name' is kept, so it must live as long as this task. // Only a pointer to 'name' is kept, so it must live as long as this task.
rust_task(rust_scheduler *sched, rust_task(rust_scheduler *sched,
rust_task_list *state, rust_task_list *state,

View file

@ -0,0 +1,7 @@
// error-pattern:ran out of stack
// Test that the task fails after hiting the recursion limit
fn main() {
main();
}

View file

@ -10,5 +10,5 @@ fn getbig(i: int) -> int {
} }
fn main() { fn main() {
getbig(100000); getbig(10000);
} }

View file

@ -37,6 +37,6 @@ fn getbig(a0: int,
} }
fn main() { fn main() {
let a = 100000; let a = 10000;
getbig(a, a+1, a+2, a+3, a+4, a+5, a+6, a+7, a+8, a+9); getbig(a, a+1, a+2, a+3, a+4, a+5, a+6, a+7, a+8, a+9);
} }

View file

@ -53,45 +53,45 @@ fn getbig(i: biggy) {
fn main() { fn main() {
getbig({ getbig({
a00: 100000u64, a00: 10000u64,
a01: 100000u64, a01: 10000u64,
a02: 100000u64, a02: 10000u64,
a03: 100000u64, a03: 10000u64,
a04: 100000u64, a04: 10000u64,
a05: 100000u64, a05: 10000u64,
a06: 100000u64, a06: 10000u64,
a07: 100000u64, a07: 10000u64,
a08: 100000u64, a08: 10000u64,
a09: 100000u64, a09: 10000u64,
a10: 100000u64, a10: 10000u64,
a11: 100000u64, a11: 10000u64,
a12: 100000u64, a12: 10000u64,
a13: 100000u64, a13: 10000u64,
a14: 100000u64, a14: 10000u64,
a15: 100000u64, a15: 10000u64,
a16: 100000u64, a16: 10000u64,
a17: 100000u64, a17: 10000u64,
a18: 100000u64, a18: 10000u64,
a19: 100000u64, a19: 10000u64,
a20: 100000u64, a20: 10000u64,
a21: 100000u64, a21: 10000u64,
a22: 100000u64, a22: 10000u64,
a23: 100000u64, a23: 10000u64,
a24: 100000u64, a24: 10000u64,
a25: 100000u64, a25: 10000u64,
a26: 100000u64, a26: 10000u64,
a27: 100000u64, a27: 10000u64,
a28: 100000u64, a28: 10000u64,
a29: 100000u64, a29: 10000u64,
a30: 100000u64, a30: 10000u64,
a31: 100000u64, a31: 10000u64,
a32: 100000u64, a32: 10000u64,
a33: 100000u64, a33: 10000u64,
a34: 100000u64, a34: 10000u64,
a35: 100000u64, a35: 10000u64,
a36: 100000u64, a36: 10000u64,
a37: 100000u64, a37: 10000u64,
a38: 100000u64, a38: 10000u64,
a39: 100000u64, a39: 10000u64,
}); });
} }

View file

@ -0,0 +1,12 @@
// error-pattern:ran out of stack
// Test that the task fails after hiting the recursion limit, but
// that it doesn't bring down the whole proc
fn main() {
task::spawn {||
task::unsupervise();
fn f() { f() };
f();
};
}