X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/e06516f565dca3636a4cbef770b191a5fcdf63ab..832390a5ed11e6c516db0986bf302d098e3ae36c:/qemu-coroutine.c diff --git a/qemu-coroutine.c b/qemu-coroutine.c index 600be2643c..bd574aa1b5 100644 --- a/qemu-coroutine.c +++ b/qemu-coroutine.c @@ -14,28 +14,92 @@ #include "trace.h" #include "qemu-common.h" -#include "qemu-coroutine.h" -#include "qemu-coroutine-int.h" +#include "qemu/thread.h" +#include "block/coroutine.h" +#include "block/coroutine_int.h" + +enum { + POOL_DEFAULT_SIZE = 64, +}; + +/** Free list to speed up creation */ +static QemuMutex pool_lock; +static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); +static unsigned int pool_size; +static unsigned int pool_max_size = POOL_DEFAULT_SIZE; Coroutine *qemu_coroutine_create(CoroutineEntry *entry) { - Coroutine *co = qemu_coroutine_new(); + Coroutine *co = NULL; + + if (CONFIG_COROUTINE_POOL) { + qemu_mutex_lock(&pool_lock); + co = QSLIST_FIRST(&pool); + if (co) { + QSLIST_REMOVE_HEAD(&pool, pool_next); + pool_size--; + } + qemu_mutex_unlock(&pool_lock); + } + + if (!co) { + co = qemu_coroutine_new(); + } + co->entry = entry; + QTAILQ_INIT(&co->co_queue_wakeup); return co; } +static void coroutine_delete(Coroutine *co) +{ + if (CONFIG_COROUTINE_POOL) { + qemu_mutex_lock(&pool_lock); + if (pool_size < pool_max_size) { + QSLIST_INSERT_HEAD(&pool, co, pool_next); + co->caller = NULL; + pool_size++; + qemu_mutex_unlock(&pool_lock); + return; + } + qemu_mutex_unlock(&pool_lock); + } + + qemu_coroutine_delete(co); +} + +static void __attribute__((constructor)) coroutine_pool_init(void) +{ + qemu_mutex_init(&pool_lock); +} + +static void __attribute__((destructor)) coroutine_pool_cleanup(void) +{ + Coroutine *co; + Coroutine *tmp; + + QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { + QSLIST_REMOVE_HEAD(&pool, pool_next); + qemu_coroutine_delete(co); + } + + qemu_mutex_destroy(&pool_lock); +} + static void coroutine_swap(Coroutine *from, Coroutine *to) { CoroutineAction ret; ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD); + qemu_co_queue_run_restart(to); + switch (ret) { case COROUTINE_YIELD: return; case COROUTINE_TERMINATE: trace_qemu_coroutine_terminate(to); - qemu_coroutine_delete(to); + coroutine_delete(to); return; default: abort(); @@ -73,3 +137,23 @@ void coroutine_fn qemu_coroutine_yield(void) self->caller = NULL; coroutine_swap(self, to); } + +void qemu_coroutine_adjust_pool_size(int n) +{ + qemu_mutex_lock(&pool_lock); + + pool_max_size += n; + + /* Callers should never take away more than they added */ + assert(pool_max_size >= POOL_DEFAULT_SIZE); + + /* Trim oversized pool down to new max */ + while (pool_size > pool_max_size) { + Coroutine *co = QSLIST_FIRST(&pool); + QSLIST_REMOVE_HEAD(&pool, pool_next); + pool_size--; + qemu_coroutine_delete(co); + } + + qemu_mutex_unlock(&pool_lock); +}