29b115
From 9c2e55d25fec6ffb21e344513b7dbeed7e21f641 Mon Sep 17 00:00:00 2001
29b115
From: Stefan Hajnoczi <stefanha@redhat.com>
29b115
Date: Tue, 17 May 2022 12:08:04 +0100
29b115
Subject: [PATCH 2/6] coroutine: use QEMU_DEFINE_STATIC_CO_TLS()
29b115
MIME-Version: 1.0
29b115
Content-Type: text/plain; charset=UTF-8
29b115
Content-Transfer-Encoding: 8bit
29b115
29b115
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
29b115
RH-MergeRequest: 89: coroutine: use coroutine TLS macros to protect thread-local variables
29b115
RH-Commit: [2/3] 68a8847e406e2eace6ddc31b0c5676a60600d606 (stefanha/centos-stream-qemu-kvm)
29b115
RH-Bugzilla: 1952483
29b115
RH-Acked-by: Hanna Reitz <hreitz@redhat.com>
29b115
RH-Acked-by: Eric Blake <eblake@redhat.com>
29b115
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
29b115
29b115
Thread-Local Storage variables cannot be used directly from coroutine
29b115
code because the compiler may optimize TLS variable accesses across
29b115
qemu_coroutine_yield() calls. When the coroutine is re-entered from
29b115
another thread the TLS variables from the old thread must no longer be
29b115
used.
29b115
29b115
Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables.
29b115
The alloc_pool QSLIST needs a typedef so the return value of
29b115
get_ptr_alloc_pool() can be stored in a local variable.
29b115
29b115
One example of why this code is necessary: a coroutine that yields
29b115
before calling qemu_coroutine_create() to create another coroutine is
29b115
affected by the TLS issue.
29b115
29b115
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29b115
Message-Id: <20220307153853.602859-3-stefanha@redhat.com>
29b115
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
29b115
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29b115
(cherry picked from commit ac387a08a9c9f6b36757da912f0339c25f421f90)
29b115
29b115
Conflicts:
29b115
- Context conflicts due to commit 5411171c3ef4 ("coroutine: Revert to
29b115
  constant batch size").
29b115
29b115
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29b115
---
29b115
 util/qemu-coroutine.c | 41 ++++++++++++++++++++++++-----------------
29b115
 1 file changed, 24 insertions(+), 17 deletions(-)
29b115
29b115
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
29b115
index 804f672e0a..4a8bd63ef0 100644
29b115
--- a/util/qemu-coroutine.c
29b115
+++ b/util/qemu-coroutine.c
29b115
@@ -18,6 +18,7 @@
29b115
 #include "qemu/atomic.h"
29b115
 #include "qemu/coroutine.h"
29b115
 #include "qemu/coroutine_int.h"
29b115
+#include "qemu/coroutine-tls.h"
29b115
 #include "block/aio.h"
29b115
 
29b115
 /**
29b115
@@ -35,17 +36,20 @@ enum {
29b115
 static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool);
29b115
 static unsigned int pool_max_size = POOL_INITIAL_MAX_SIZE;
29b115
 static unsigned int release_pool_size;
29b115
-static __thread QSLIST_HEAD(, Coroutine) alloc_pool = QSLIST_HEAD_INITIALIZER(pool);
29b115
-static __thread unsigned int alloc_pool_size;
29b115
-static __thread Notifier coroutine_pool_cleanup_notifier;
29b115
+
29b115
+typedef QSLIST_HEAD(, Coroutine) CoroutineQSList;
29b115
+QEMU_DEFINE_STATIC_CO_TLS(CoroutineQSList, alloc_pool);
29b115
+QEMU_DEFINE_STATIC_CO_TLS(unsigned int, alloc_pool_size);
29b115
+QEMU_DEFINE_STATIC_CO_TLS(Notifier, coroutine_pool_cleanup_notifier);
29b115
 
29b115
 static void coroutine_pool_cleanup(Notifier *n, void *value)
29b115
 {
29b115
     Coroutine *co;
29b115
     Coroutine *tmp;
29b115
+    CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
29b115
 
29b115
-    QSLIST_FOREACH_SAFE(co, &alloc_pool, pool_next, tmp) {
29b115
-        QSLIST_REMOVE_HEAD(&alloc_pool, pool_next);
29b115
+    QSLIST_FOREACH_SAFE(co, alloc_pool, pool_next, tmp) {
29b115
+        QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
29b115
         qemu_coroutine_delete(co);
29b115
     }
29b115
 }
29b115
@@ -55,27 +59,30 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque)
29b115
     Coroutine *co = NULL;
29b115
 
29b115
     if (CONFIG_COROUTINE_POOL) {
29b115
-        co = QSLIST_FIRST(&alloc_pool);
29b115
+        CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
29b115
+
29b115
+        co = QSLIST_FIRST(alloc_pool);
29b115
         if (!co) {
29b115
             if (release_pool_size > POOL_MIN_BATCH_SIZE) {
29b115
                 /* Slow path; a good place to register the destructor, too.  */
29b115
-                if (!coroutine_pool_cleanup_notifier.notify) {
29b115
-                    coroutine_pool_cleanup_notifier.notify = coroutine_pool_cleanup;
29b115
-                    qemu_thread_atexit_add(&coroutine_pool_cleanup_notifier);
29b115
+                Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier();
29b115
+                if (!notifier->notify) {
29b115
+                    notifier->notify = coroutine_pool_cleanup;
29b115
+                    qemu_thread_atexit_add(notifier);
29b115
                 }
29b115
 
29b115
                 /* This is not exact; there could be a little skew between
29b115
                  * release_pool_size and the actual size of release_pool.  But
29b115
                  * it is just a heuristic, it does not need to be perfect.
29b115
                  */
29b115
-                alloc_pool_size = qatomic_xchg(&release_pool_size, 0);
29b115
-                QSLIST_MOVE_ATOMIC(&alloc_pool, &release_pool);
29b115
-                co = QSLIST_FIRST(&alloc_pool);
29b115
+                set_alloc_pool_size(qatomic_xchg(&release_pool_size, 0));
29b115
+                QSLIST_MOVE_ATOMIC(alloc_pool, &release_pool);
29b115
+                co = QSLIST_FIRST(alloc_pool);
29b115
             }
29b115
         }
29b115
         if (co) {
29b115
-            QSLIST_REMOVE_HEAD(&alloc_pool, pool_next);
29b115
-            alloc_pool_size--;
29b115
+            QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
29b115
+            set_alloc_pool_size(get_alloc_pool_size() - 1);
29b115
         }
29b115
     }
29b115
 
29b115
@@ -99,9 +106,9 @@ static void coroutine_delete(Coroutine *co)
29b115
             qatomic_inc(&release_pool_size);
29b115
             return;
29b115
         }
29b115
-        if (alloc_pool_size < qatomic_read(&pool_max_size)) {
29b115
-            QSLIST_INSERT_HEAD(&alloc_pool, co, pool_next);
29b115
-            alloc_pool_size++;
29b115
+        if (get_alloc_pool_size() < qatomic_read(&pool_max_size)) {
29b115
+            QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next);
29b115
+            set_alloc_pool_size(get_alloc_pool_size() + 1);
29b115
             return;
29b115
         }
29b115
     }
29b115
-- 
29b115
2.31.1
29b115