diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/coroutine-sigaltstack.c | 25 | ||||
-rw-r--r-- | util/coroutine-ucontext.c | 11 | ||||
-rw-r--r-- | util/coroutine-win32.c | 2 | ||||
-rw-r--r-- | util/oslib-posix.c | 77 |
4 files changed, 97 insertions, 18 deletions
diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index a7c3366553..f6fc49a0e5 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -33,8 +33,9 @@ typedef struct { Coroutine base; void *stack; + size_t stack_size; sigjmp_buf env; -} CoroutineUContext; +} CoroutineSigAltStack; /** * Per-thread coroutine bookkeeping @@ -44,7 +45,7 @@ typedef struct { Coroutine *current; /** The default coroutine */ - CoroutineUContext leader; + CoroutineSigAltStack leader; /** Information for the signal handler (trampoline) */ sigjmp_buf tr_reenter; @@ -89,7 +90,7 @@ static void __attribute__((constructor)) coroutine_init(void) * (from the signal handler when it is not signal handling, read ahead * for more information). */ -static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) +static void coroutine_bootstrap(CoroutineSigAltStack *self, Coroutine *co) { /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { @@ -109,7 +110,7 @@ static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) */ static void coroutine_trampoline(int signal) { - CoroutineUContext *self; + CoroutineSigAltStack *self; Coroutine *co; CoroutineThreadState *coTS; @@ -143,8 +144,7 @@ static void coroutine_trampoline(int signal) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; - CoroutineUContext *co; + CoroutineSigAltStack *co; CoroutineThreadState *coTS; struct sigaction sa; struct sigaction osa; @@ -164,7 +164,8 @@ Coroutine *qemu_coroutine_new(void) */ co = g_malloc0(sizeof(*co)); - co->stack = g_malloc(stack_size); + co->stack_size = COROUTINE_STACK_SIZE; + co->stack = qemu_alloc_stack(&co->stack_size); co->base.entry_arg = &old_env; /* stash away our jmp_buf */ coTS = coroutine_get_thread_state(); @@ -189,7 +190,7 @@ Coroutine *qemu_coroutine_new(void) * Set the new stack. */ ss.ss_sp = co->stack; - ss.ss_size = stack_size; + ss.ss_size = co->stack_size; ss.ss_flags = 0; if (sigaltstack(&ss, &oss) < 0) { abort(); @@ -251,17 +252,17 @@ Coroutine *qemu_coroutine_new(void) void qemu_coroutine_delete(Coroutine *co_) { - CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); + CoroutineSigAltStack *co = DO_UPCAST(CoroutineSigAltStack, base, co_); - g_free(co->stack); + qemu_free_stack(co->stack, co->stack_size); g_free(co); } CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineAction action) { - CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); - CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); + CoroutineSigAltStack *from = DO_UPCAST(CoroutineSigAltStack, base, from_); + CoroutineSigAltStack *to = DO_UPCAST(CoroutineSigAltStack, base, to_); CoroutineThreadState *s = coroutine_get_thread_state(); int ret; diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 2bb7e10d4b..6621f3f692 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -34,6 +34,7 @@ typedef struct { Coroutine base; void *stack; + size_t stack_size; sigjmp_buf env; #ifdef CONFIG_VALGRIND_H @@ -82,7 +83,6 @@ static void coroutine_trampoline(int i0, int i1) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; CoroutineUContext *co; ucontext_t old_uc, uc; sigjmp_buf old_env; @@ -101,17 +101,18 @@ Coroutine *qemu_coroutine_new(void) } co = g_malloc0(sizeof(*co)); - co->stack = g_malloc(stack_size); + co->stack_size = COROUTINE_STACK_SIZE; + co->stack = qemu_alloc_stack(&co->stack_size); co->base.entry_arg = &old_env; /* stash away our jmp_buf */ uc.uc_link = &old_uc; uc.uc_stack.ss_sp = co->stack; - uc.uc_stack.ss_size = stack_size; + uc.uc_stack.ss_size = co->stack_size; uc.uc_stack.ss_flags = 0; #ifdef CONFIG_VALGRIND_H co->valgrind_stack_id = - VALGRIND_STACK_REGISTER(co->stack, co->stack + stack_size); + VALGRIND_STACK_REGISTER(co->stack, co->stack + co->stack_size); #endif arg.p = co; @@ -149,7 +150,7 @@ void qemu_coroutine_delete(Coroutine *co_) valgrind_stack_deregister(co); #endif - g_free(co->stack); + qemu_free_stack(co->stack, co->stack_size); g_free(co); } diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c index 02e28e825f..de6bd4fd3e 100644 --- a/util/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -71,7 +71,7 @@ static void CALLBACK coroutine_trampoline(void *co_) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; + const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineWin32 *co; co = g_malloc0(sizeof(*co)); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 8c1e8d6841..8ec99ccb4f 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -51,6 +51,10 @@ #include "qemu/mmap-alloc.h" +#ifdef CONFIG_DEBUG_STACK_USAGE +#include "qemu/error-report.h" +#endif + int qemu_get_thread_id(void) { #if defined(__linux__) @@ -526,3 +530,76 @@ pid_t qemu_fork(Error **errp) } return pid; } + +void *qemu_alloc_stack(size_t *sz) +{ + void *ptr, *guardpage; +#ifdef CONFIG_DEBUG_STACK_USAGE + void *ptr2; +#endif + size_t pagesz = getpagesize(); +#ifdef _SC_THREAD_STACK_MIN + /* avoid stacks smaller than _SC_THREAD_STACK_MIN */ + long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN); + *sz = MAX(MAX(min_stack_sz, 0), *sz); +#endif + /* adjust stack size to a multiple of the page size */ + *sz = ROUND_UP(*sz, pagesz); + /* allocate one extra page for the guard page */ + *sz += pagesz; + + ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) { + abort(); + } + +#if defined(HOST_IA64) + /* separate register stack */ + guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz); +#elif defined(HOST_HPPA) + /* stack grows up */ + guardpage = ptr + *sz - pagesz; +#else + /* stack grows down */ + guardpage = ptr; +#endif + if (mprotect(guardpage, pagesz, PROT_NONE) != 0) { + abort(); + } + +#ifdef CONFIG_DEBUG_STACK_USAGE + for (ptr2 = ptr + pagesz; ptr2 < ptr + *sz; ptr2 += sizeof(uint32_t)) { + *(uint32_t *)ptr2 = 0xdeadbeaf; + } +#endif + + return ptr; +} + +#ifdef CONFIG_DEBUG_STACK_USAGE +static __thread unsigned int max_stack_usage; +#endif + +void qemu_free_stack(void *stack, size_t sz) +{ +#ifdef CONFIG_DEBUG_STACK_USAGE + unsigned int usage; + void *ptr; + + for (ptr = stack + getpagesize(); ptr < stack + sz; + ptr += sizeof(uint32_t)) { + if (*(uint32_t *)ptr != 0xdeadbeaf) { + break; + } + } + usage = sz - (uintptr_t) (ptr - stack); + if (usage > max_stack_usage) { + error_report("thread %d max stack usage increased from %u to %u", + qemu_get_thread_id(), max_stack_usage, usage); + max_stack_usage = usage; + } +#endif + + munmap(stack, sz); +} |