X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/aec7c6dc683314d1e5bed09a9cc98dab086ead82..79ee7df8853c5d7085d87036420b6b388dda2595:/coroutine-ucontext.c diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 2b8d3e9c12..784081ab18 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -30,15 +30,28 @@ #include "qemu-common.h" #include "qemu-coroutine-int.h" +#ifdef CONFIG_VALGRIND_H +#include +#endif + enum { /* Maximum free pool size prevents holding too many freed coroutines */ POOL_MAX_SIZE = 64, }; +/** Free list to speed up creation */ +static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); +static unsigned int pool_size; + typedef struct { Coroutine base; void *stack; jmp_buf env; + +#ifdef CONFIG_VALGRIND_H + unsigned int valgrind_stack_id; +#endif + } CoroutineUContext; /** @@ -48,10 +61,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; @@ -75,7 +84,6 @@ static CoroutineThreadState *coroutine_get_thread_state(void) if (!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 +92,19 @@ static CoroutineThreadState *coroutine_get_thread_state(void) static void qemu_coroutine_thread_cleanup(void *opaque) { CoroutineThreadState *s = opaque; + + g_free(s); +} + +static void __attribute__((destructor)) coroutine_cleanup(void) +{ Coroutine *co; Coroutine *tmp; - QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) { + QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { g_free(DO_UPCAST(CoroutineUContext, base, co)->stack); g_free(co); } - g_free(s); } static void __attribute__((constructor)) coroutine_init(void) @@ -155,6 +168,11 @@ 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, @@ -169,31 +187,47 @@ static Coroutine *coroutine_new(void) Coroutine *qemu_coroutine_new(void) { - CoroutineThreadState *s = coroutine_get_thread_state(); Coroutine *co; - co = QLIST_FIRST(&s->pool); + co = QSLIST_FIRST(&pool); if (co) { - QLIST_REMOVE(co, pool_next); - s->pool_size--; + QSLIST_REMOVE_HEAD(&pool, pool_next); + pool_size--; } else { co = coroutine_new(); } return co; } +#ifdef CONFIG_VALGRIND_H +#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +/* Work around an unused variable in the valgrind.h macro... */ +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif +static inline void valgrind_stack_deregister(CoroutineUContext *co) +{ + VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); +} +#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +#pragma GCC diagnostic error "-Wunused-but-set-variable" +#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); + if (pool_size < POOL_MAX_SIZE) { + QSLIST_INSERT_HEAD(&pool, &co->base, pool_next); co->base.caller = NULL; - s->pool_size++; + pool_size++; return; } +#ifdef CONFIG_VALGRIND_H + valgrind_stack_deregister(co); +#endif + g_free(co->stack); g_free(co); }