rt: More work on morestack

This commit is contained in:
Patrick Walton 2011-11-14 13:52:35 -08:00 committed by Brian Anderson
parent 8199558443
commit 68aff2ad6d
6 changed files with 143 additions and 29 deletions

View File

@ -67,7 +67,8 @@ RUNTIME_CS_$(1) := \
RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \
rt/arch/$$(HOST_$(1))/ccall.S \
rt/arch/$$(HOST_$(1))/morestack.S
rt/arch/$$(HOST_$(1))/morestack.S \
rt/arch/$$(HOST_$(1))/record_sp.S
RUNTIME_HDR_$(1) := rt/globals.h \
rt/rust.h \

View File

@ -2,40 +2,117 @@
// __morestack
//
// LLVM generates a call to this to allocate more stack space in a functiono
// LLVM generates a call to this to allocate more stack space in a function
// prolog when we run out.
#if defined(__APPLE__) || defined(_WIN32)
#define RUST_NEW_STACK _rust_new_stack
#define RUST_DEL_STACK _rust_del_stack
#define MORESTACK ___morestack
#define RUST_NEW_STACK _rust_new_stack
#define RUST_DEL_STACK _rust_del_stack
#define RUST_GET_PREV_STACK _rust_get_prev_stack
#define RUST_GET_TASK _rust_get_task
#define UPCALL_ALLOC_C_STACK _upcall_alloc_c_stack
#define UPCALL_CALL_C_STACK _upcall_call_c_stack
#define MORESTACK ___morestack
#else
#define RUST_NEW_STACK rust_new_stack
#define RUST_DEL_STACK rust_del_stack
#define MORESTACK __morestack
#define RUST_NEW_STACK rust_new_stack
#define RUST_DEL_STACK rust_del_stack
#define RUST_GET_PREV_STACK rust_get_prev_stack
#define RUST_GET_TASK rust_get_task
#define UPCALL_ALLOC_C_STACK upcall_alloc_c_stack
#define UPCALL_CALL_C_STACK upcall_call_c_stack
#define MORESTACK __morestack
#endif
#ifdef __APPLE__
#define ALIGNMENT 4
#else
#define ALIGNMENT 8
#endif
#define RETURN_OFFSET 7
.globl RUST_NEW_STACK
.globl RUST_DEL_STACK
.globl RUST_GET_PREV_STACK
.globl RUST_GET_TASK
.globl UPCALL_ALLOC_C_STACK
.globl UPCALL_CALL_C_STACK
.globl MORESTACK
MORESTACK:
pushl 8(%esp) // argsz > ra stksz argsz x x ra args
leal 28(%esp),%eax // argsz ra stksz argsz x x ra args
pushl %eax // argp > argsz ra stksz argsz x x ra args
pushl 12(%esp) // stksz > argp argsz ra stksz argsz x x ra args
calll RUST_NEW_STACK
addl $12,%esp // ra stksz argsz x x ra args
movl (%esp),%edx // Grab the return pointer.
incl %edx // Skip past the `ret`.
movl %eax,%esp // Switch to the new stack.
// Sanity check to make sure that there is a currently-running task.
subl $12,%esp
calll RUST_GET_TASK
testl %eax,%eax
jz L$bail
subl $12,%esp
pushl $12
calll UPCALL_ALLOC_C_STACK
movl %eax,%edx
// C stack | esp+12
// ---------------------+-------------------------
movl 20(%esp),%eax // | ra stksz argsz x ra args
movl %eax,8(%edx) // argsz > | ra stksz argsz x ra args
leal 32(%esp),%eax // argsz | ra stksz argsz x ra args
movl %eax,4(%edx) // argp > argsz | ra stksz argsz x ra args
movl 16(%esp),%eax // argp argsz | ra stksz argsz x ra args
movl %eax,(%edx) // stksz > argp argsz | ra stksz argsz x ra args
calll L$pic_ref_pt_0
L$pic_ref_pt_0:
popl %eax
movl rust_new_stack_sym-L$pic_ref_pt_0(%eax),%eax
movl %eax,(%esp)
movl %edx,4(%esp)
calll UPCALL_CALL_C_STACK
movl 16(%esp),%edx // Grab the return pointer.
addl $RETURN_OFFSET,%edx // Skip past the `add esp,4` and the `ret`.
movl %eax,%esp // Switch stacks.
subl $12,%esp // Align the stack.
calll *%edx // Re-enter the function that called us.
// Now the function that called us has returned, so we need to delete the
// old stack space.
calll RUST_DEL_STACK
movl %eax,%esp
retl $8 // ra stksz argsz x x ra args
calll RUST_GET_PREV_STACK
movl %eax,%esp // Switch back to the old stack.
movl $0,(%esp)
calll UPCALL_ALLOC_C_STACK
calll L$pic_ref_pt_1
L$pic_ref_pt_1:
popl %edx
movl rust_del_stack_sym-L$pic_ref_pt_1(%edx),%edx
movl %edx,(%esp)
movl %eax,4(%esp)
calll UPCALL_CALL_C_STACK
addl $16,%esp
retl $16 + ALIGNMENT // ra stksz argsz x ra args
L$bail:
movl 12(%esp),%edx
addl $RETURN_OFFSET,%edx
addl $12+16,%esp
jmpl *%edx
#ifdef __APPLE__
.section __IMPORT,__pointers,non_lazy_symbol_pointers
rust_new_stack_sym:
.indirect_symbol RUST_NEW_STACK
.long 0
rust_del_stack_sym:
.indirect_symbol RUST_DEL_STACK
.long 0
#endif

View File

@ -1,4 +1,5 @@
#include "rust_internal.h"
#include <cstdio>
struct
command_line_args : public kernel_owned<command_line_args>
@ -75,6 +76,8 @@ int check_claims = 0;
extern "C" CDECL int
rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
fprintf(stderr, "rust_start, argc=%d argv=%p\n", argc, argv);
rust_env *env = load_env();
update_log_settings(crate_map, env->logspec);

View File

@ -1,6 +1,7 @@
#include <stdarg.h>
#include <cassert>
#include <pthread.h>
#include "rust_internal.h"
#include "globals.h"
@ -12,6 +13,9 @@ DWORD rust_scheduler::task_key;
bool rust_scheduler::tls_initialized = false;
// Defined in arch/*/record_sp.S.
extern "C" void rust_record_sp(uintptr_t sp);
rust_scheduler::rust_scheduler(rust_kernel *kernel,
rust_srv *srv,
int id) :
@ -285,6 +289,8 @@ rust_scheduler::start_main_loop() {
scheduled_task->state->name);
place_task_in_tls(scheduled_task);
rust_record_sp(scheduled_task->stk->limit);
//pthread_setspecific(89, (void *)scheduled_task->stk->limit);
interrupt_flag = 0;
@ -374,6 +380,8 @@ rust_scheduler::place_task_in_tls(rust_task *task) {
rust_task *
rust_scheduler::get_task() {
if (!tls_initialized)
return NULL;
rust_task *task = reinterpret_cast<rust_task *>
(pthread_getspecific(task_key));
assert(task && "Couldn't get the task from TLS!");
@ -395,6 +403,8 @@ rust_scheduler::place_task_in_tls(rust_task *task) {
rust_task *
rust_scheduler::get_task() {
if (!tls_initialized)
return NULL;
rust_task *task = reinterpret_cast<rust_task *>(TlsGetValue(task_key));
assert(task && "Couldn't get the task from TLS!");
return task;

View File

@ -8,11 +8,14 @@
#ifndef __WIN32__
#include <execinfo.h>
#endif
#include <iostream>
#include <cassert>
#include <cstring>
#include "globals.h"
#define RED_ZONE_SIZE 128
// Stack size
size_t g_custom_min_stack_size = 0;
@ -34,16 +37,16 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz)
size_t min_stk_bytes = get_min_stk_size(sched->min_stack_size);
if (minsz < min_stk_bytes)
minsz = min_stk_bytes;
size_t sz = sizeof(stk_seg) + minsz;
size_t sz = sizeof(stk_seg) + minsz + RED_ZONE_SIZE;
stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
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];
stk->limit = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE];
LOGPTR(task->sched, "stk limit", stk->limit);
stk->valgrind_id =
VALGRIND_STACK_REGISTER(&stk->data[0],
&stk->data[minsz]);
&stk->data[minsz + RED_ZONE_SIZE]);
task->stk = stk;
return stk;
}
@ -63,18 +66,32 @@ del_stk(rust_task *task, stk_seg *stk)
// Entry points for `__morestack` (see arch/*/morestack.S).
extern "C" void *
rust_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
std::cerr << "*** New stack!\n";
rust_task *task = rust_scheduler::get_task();
if (!task)
return NULL;
stk_seg *stk_seg = new_stk(task->sched, task, stk_sz);
memcpy(stk_seg->data, args_addr, args_sz);
return stk_seg->data;
}
extern "C" void *
extern "C" void
rust_del_stack() {
rust_task *task = rust_scheduler::get_task();
stk_seg *next_seg = task->stk->next;
del_stk(task, task->stk);
return next_seg->data;
}
extern "C" void *
rust_get_prev_stack() {
rust_task *task = rust_scheduler::get_task();
return task->stk->next;
}
extern "C" rust_task *
rust_get_task() {
return rust_scheduler::get_task();
}

View File

@ -1,3 +1,4 @@
__morestack
align_of
chan_id_send
check_claims
@ -28,7 +29,10 @@ rand_free
rand_new
rand_next
refcount
rust_del_stack
rust_file_is_dir
rust_getcwd
rust_get_prev_stack
rust_get_stdin
rust_get_stdout
rust_get_stderr
@ -36,12 +40,14 @@ rust_str_push
rust_list_files
rust_port_detach
rust_port_size
rust_new_stack
rust_process_wait
rust_ptr_eq
rust_run_program
rust_start
rust_getcwd
rust_task_sleep
rust_get_task
set_min_stack
sched_threads
size_of
@ -63,10 +69,10 @@ upcall_dynastack_mark
upcall_fail
upcall_free
upcall_get_type_desc
upcall_vec_grow
upcall_vec_push
upcall_log_type
upcall_malloc
upcall_rust_personality
upcall_shared_malloc
upcall_shared_free
upcall_vec_grow
upcall_vec_push