From 9a738fd61d3006796d518ba751f5bb632f65edb6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 16:26:47 -0800 Subject: rt: Various tweaks to make __morestack unwinding work on linux When unwinding through __morestack the stack limit in the TLS is invalidated and must be reset. Instead of actually landing at __morestack we're just going to make all our Rust landing pads call upcall_reset_stack_limit, which will find the stack segment that corresponds to the current stack pointer and put the limit in the TLS. Also massively expand the stack segment red zone to make more room for the dynamic linker. Will fix in the future. --- src/rt/rust_task.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src/rt/rust_task.cpp') diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index b540225243f..888c9ac701a 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -18,11 +18,11 @@ // to the rt, compiler and dynamic linker for running small functions // FIXME: We want this to be 128 but need to slim the red zone calls down #ifdef __i386__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif #ifdef __x86_64__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif // Stack size @@ -613,6 +613,29 @@ rust_task::record_stack_limit() { "Stack size must be greater than LIMIT_OFFSET"); record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); } + +extern "C" uintptr_t get_sp(); + +/* +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). + */ +void +rust_task::reset_stack_limit() { + uintptr_t sp = get_sp(); + // Not positive these bounds for sp are correct. + // I think that the first possible value for esp on a new + // stack is stk->limit, which points one word in front of + // the first work to be pushed onto a new stack. + while (sp <= (uintptr_t)stk->data || stk->limit < sp) { + del_stk(this, stk); + A(sched, stk != NULL, "Failed to find the current stack"); + } + record_stack_limit(); +} + // // Local Variables: // mode: C++ -- cgit 1.4.1-3-g733a5 From 5d1a1dc4203f8ae77e2e9c5cba393887f0b7d762 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 17:03:54 -0800 Subject: rt: Rename stk_seg.limit to stk_seg.end rust_task is using the word limit it two ways, so one has to change. --- src/rt/rust_scheduler.cpp | 1 - src/rt/rust_task.cpp | 14 +++++++------- src/rt/rust_task.h | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/rt/rust_task.cpp') diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 42b2e490404..601a7c3f0ef 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -286,7 +286,6 @@ rust_scheduler::start_main_loop() { scheduled_task->state->name); place_task_in_tls(scheduled_task); - //pthread_setspecific(89, (void *)scheduled_task->stk->limit); interrupt_flag = 0; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 888c9ac701a..0f97a0a6853 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -51,8 +51,8 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) LOGPTR(task->sched, "new stk", (uintptr_t)stk); memset(stk, 0, sizeof(stk_seg)); stk->next = task->stk; - stk->limit = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE]; - LOGPTR(task->sched, "stk limit", stk->limit); + stk->end = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE]; + LOGPTR(task->sched, "stk end", stk->end); stk->valgrind_id = VALGRIND_STACK_REGISTER(&stk->data[0], &stk->data[minsz + RED_ZONE_SIZE]); @@ -106,7 +106,7 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state, user.notify_enabled = 0; stk = new_stk(sched, this, 0); - user.rust_sp = stk->limit; + user.rust_sp = stk->end; if (supervisor) { supervisor->ref(); } @@ -582,7 +582,7 @@ rust_task::new_stack(size_t stk_sz, void *args_addr, size_t args_sz) { stk_seg *stk_seg = new_stk(sched, this, stk_sz + args_sz); - uint8_t *new_sp = (uint8_t*)stk_seg->limit; + uint8_t *new_sp = (uint8_t*)stk_seg->end; size_t sizeof_retaddr = sizeof(void*); // Make enough room on the new stack to hold the old stack pointer // in addition to the function arguments @@ -608,7 +608,7 @@ rust_task::record_stack_limit() { // account for those 256 bytes. const unsigned LIMIT_OFFSET = 256; A(sched, - (uintptr_t)stk->limit - RED_ZONE_SIZE + (uintptr_t)stk->end - RED_ZONE_SIZE - (uintptr_t)stk->data >= LIMIT_OFFSET, "Stack size must be greater than LIMIT_OFFSET"); record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); @@ -627,9 +627,9 @@ rust_task::reset_stack_limit() { uintptr_t sp = get_sp(); // Not positive these bounds for sp are correct. // I think that the first possible value for esp on a new - // stack is stk->limit, which points one word in front of + // stack is stk->end, which points one word in front of // the first work to be pushed onto a new stack. - while (sp <= (uintptr_t)stk->data || stk->limit < sp) { + while (sp <= (uintptr_t)stk->data || stk->end < sp) { del_stk(this, stk); A(sched, stk != NULL, "Failed to find the current stack"); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 47472801510..3d5cbff9910 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -25,7 +25,7 @@ struct rust_box; struct stk_seg { stk_seg *next; - uintptr_t limit; + uintptr_t end; unsigned int valgrind_id; #ifndef _LP64 uint32_t pad; -- cgit 1.4.1-3-g733a5 From 9656ceac60258c4189c31b402def67039ae17822 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 17:19:24 -0800 Subject: rt: Put 16 guard bytes at the end of the stack --- src/rt/rust_task.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/rt/rust_task.cpp') diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 0f97a0a6853..bdc2f7ff7ce 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -14,15 +14,22 @@ #include "globals.h" +// Each stack gets some guard bytes that valgrind will verify we don't touch +#ifndef NVALGRIND +#define STACK_NOACCESS_SIZE 16 +#else +#define STACK_NOACCESS_SIZE 0 +#endif + // The amount of extra space at the end of each stack segment, available // to the rt, compiler and dynamic linker for running small functions // FIXME: We want this to be 128 but need to slim the red zone calls down #ifdef __i386__ -#define RED_ZONE_SIZE 65536 +#define RED_ZONE_SIZE (65536 + STACK_NOACCESS_SIZE) #endif #ifdef __x86_64__ -#define RED_ZONE_SIZE 65536 +#define RED_ZONE_SIZE (65536 + STACK_NOACCESS_SIZE) #endif // Stack size @@ -56,6 +63,9 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) stk->valgrind_id = VALGRIND_STACK_REGISTER(&stk->data[0], &stk->data[minsz + RED_ZONE_SIZE]); +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_NOACCESS(stk->data, STACK_NOACCESS_SIZE); +#endif task->stk = stk; return stk; } @@ -67,6 +77,9 @@ del_stk(rust_task *task, stk_seg *stk) task->stk = stk->next; +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_DEFINED(stk->data, STACK_NOACCESS_SIZE); +#endif VALGRIND_STACK_DEREGISTER(stk->valgrind_id); LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk); task->free(stk); -- cgit 1.4.1-3-g733a5