X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=coroutine-ucontext.c;h=4bf2cde279b9ccab0d4b5e8b7b18948402a39749;hb=60aad298cb6de52f2716b2e82e1353ea9de95fd6;hp=41c2379a2a5558900a1937aa7ee3ccebd85386d8;hpb=dfa79e8acd0ffce337d78f3e1473647f1c38dc58;p=qemu.git diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 41c2379a2..4bf2cde27 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -28,17 +28,21 @@ #include #include #include "qemu-common.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine_int.h" -enum { - /* Maximum free pool size prevents holding too many freed coroutines */ - POOL_MAX_SIZE = 64, -}; +#ifdef CONFIG_VALGRIND_H +#include +#endif typedef struct { Coroutine base; void *stack; - jmp_buf env; + sigjmp_buf env; + +#ifdef CONFIG_VALGRIND_H + unsigned int valgrind_stack_id; +#endif + } CoroutineUContext; /** @@ -48,10 +52,6 @@ typedef struct { /** Currently executing coroutine */ Coroutine *current; - /** Free list to speed up creation */ - QLIST_HEAD(, Coroutine) pool; - unsigned int pool_size; - /** The default coroutine */ CoroutineUContext leader; } CoroutineThreadState; @@ -73,9 +73,8 @@ static CoroutineThreadState *coroutine_get_thread_state(void) CoroutineThreadState *s = pthread_getspecific(thread_state_key); if (!s) { - s = qemu_mallocz(sizeof(*s)); + s = g_malloc0(sizeof(*s)); s->current = &s->leader.base; - QLIST_INIT(&s->pool); pthread_setspecific(thread_state_key, s); } return s; @@ -84,14 +83,8 @@ static CoroutineThreadState *coroutine_get_thread_state(void) static void qemu_coroutine_thread_cleanup(void *opaque) { CoroutineThreadState *s = opaque; - Coroutine *co; - Coroutine *tmp; - QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) { - qemu_free(DO_UPCAST(CoroutineUContext, base, co)->stack); - qemu_free(co); - } - qemu_free(s); + g_free(s); } static void __attribute__((constructor)) coroutine_init(void) @@ -117,8 +110,8 @@ static void coroutine_trampoline(int i0, int i1) co = &self->base; /* Initialize longjmp environment and switch back the caller */ - if (!setjmp(self->env)) { - longjmp(*(jmp_buf *)co->entry_arg, 1); + if (!sigsetjmp(self->env, 0)) { + siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } while (true) { @@ -127,27 +120,28 @@ static void coroutine_trampoline(int i0, int i1) } } -static Coroutine *coroutine_new(void) +Coroutine *qemu_coroutine_new(void) { const size_t stack_size = 1 << 20; CoroutineUContext *co; ucontext_t old_uc, uc; - jmp_buf old_env; - union cc_arg arg; - - /* The ucontext functions preserve signal masks which incurs a system call - * overhead. setjmp()/longjmp() does not preserve signal masks but only - * works on the current stack. Since we need a way to create and switch to - * a new stack, use the ucontext functions for that but setjmp()/longjmp() - * for everything else. + sigjmp_buf old_env; + union cc_arg arg = {0}; + + /* The ucontext functions preserve signal masks which incurs a + * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not + * preserve signal masks but only works on the current stack. + * Since we need a way to create and switch to a new stack, use + * the ucontext functions for that but sigsetjmp()/siglongjmp() for + * everything else. */ if (getcontext(&uc) == -1) { abort(); } - co = qemu_mallocz(sizeof(*co)); - co->stack = qemu_malloc(stack_size); + co = g_malloc0(sizeof(*co)); + co->stack = g_malloc(stack_size); co->base.entry_arg = &old_env; /* stash away our jmp_buf */ uc.uc_link = &old_uc; @@ -155,47 +149,48 @@ static Coroutine *coroutine_new(void) uc.uc_stack.ss_size = 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); +#endif + arg.p = co; makecontext(&uc, (void (*)(void))coroutine_trampoline, 2, arg.i[0], arg.i[1]); - /* swapcontext() in, longjmp() back out */ - if (!setjmp(old_env)) { + /* swapcontext() in, siglongjmp() back out */ + if (!sigsetjmp(old_env, 0)) { swapcontext(&old_uc, &uc); } return &co->base; } -Coroutine *qemu_coroutine_new(void) +#ifdef CONFIG_VALGRIND_H +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +/* Work around an unused variable in the valgrind.h macro... */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif +static inline void valgrind_stack_deregister(CoroutineUContext *co) { - CoroutineThreadState *s = coroutine_get_thread_state(); - Coroutine *co; - - co = QLIST_FIRST(&s->pool); - if (co) { - QLIST_REMOVE(co, pool_next); - s->pool_size--; - } else { - co = coroutine_new(); - } - return co; + VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); } +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic pop +#endif +#endif void qemu_coroutine_delete(Coroutine *co_) { - CoroutineThreadState *s = coroutine_get_thread_state(); CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); - if (s->pool_size < POOL_MAX_SIZE) { - QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next); - co->base.caller = NULL; - s->pool_size++; - return; - } +#ifdef CONFIG_VALGRIND_H + valgrind_stack_deregister(co); +#endif - qemu_free(co->stack); - qemu_free(co); + g_free(co->stack); + g_free(co); } CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, @@ -208,9 +203,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, s->current = to_; - ret = setjmp(from->env); + ret = sigsetjmp(from->env, 0); if (ret == 0) { - longjmp(to->env, action); + siglongjmp(to->env, action); } return ret; }