]> git.proxmox.com Git - qemu.git/blobdiff - qemu-coroutine.c
Open 2.0 development tree
[qemu.git] / qemu-coroutine.c
index 0f6e2685749584e0a52dd25e23d5207c84f03e61..470852100af1eb58e69f44d91cf29a11df7cff93 100644 (file)
 
 #include "trace.h"
 #include "qemu-common.h"
+#include "qemu/thread.h"
 #include "block/coroutine.h"
 #include "block/coroutine_int.h"
 
+enum {
+    /* Maximum free pool size prevents holding too many freed coroutines */
+    POOL_MAX_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;
+
 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();