]> git.proxmox.com Git - qemu.git/blobdiff - thread-pool.c
target-mips: Fix incorrect reads and writes to DSPControl register
[qemu.git] / thread-pool.c
index 80749b77e026166186ee8e115ab00870eec9cb53..e3ca64d790ad944ca96ba0b5dbea61614776f989 100644 (file)
  * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "qemu-common.h"
-#include "qemu-queue.h"
-#include "qemu-thread.h"
-#include "osdep.h"
-#include "qemu-coroutine.h"
+#include "qemu/queue.h"
+#include "qemu/thread.h"
+#include "qemu/osdep.h"
+#include "block/coroutine.h"
 #include "trace.h"
-#include "block_int.h"
-#include "event_notifier.h"
-#include "thread-pool.h"
+#include "block/block_int.h"
+#include "qemu/event_notifier.h"
+#include "block/thread-pool.h"
 
 static void do_spawn_thread(void);
 
@@ -39,6 +39,11 @@ struct ThreadPoolElement {
     BlockDriverAIOCB common;
     ThreadPoolFunc *func;
     void *arg;
+
+    /* Moving state out of THREAD_QUEUED is protected by lock.  After
+     * that, only the worker thread can write to it.  Reads and writes
+     * of state and ret are ordered with memory barriers.
+     */
     enum ThreadState state;
     int ret;
 
@@ -95,9 +100,12 @@ static void *worker_thread(void *unused)
 
         ret = req->func(req->arg);
 
-        qemu_mutex_lock(&lock);
-        req->state = THREAD_DONE;
         req->ret = ret;
+        /* Write ret before state.  */
+        smp_wmb();
+        req->state = THREAD_DONE;
+
+        qemu_mutex_lock(&lock);
         if (pending_cancellations) {
             qemu_cond_broadcast(&check_cancel);
         }
@@ -162,11 +170,10 @@ restart:
             trace_thread_pool_complete(elem, elem->common.opaque, elem->ret);
         }
         if (elem->state == THREAD_DONE && elem->common.cb) {
-            qemu_mutex_lock(&lock);
-            int ret = elem->ret;
-            qemu_mutex_unlock(&lock);
             QLIST_REMOVE(elem, all);
-            elem->common.cb(elem->common.opaque, ret);
+            /* Read state before ret.  */
+            smp_rmb();
+            elem->common.cb(elem->common.opaque, elem->ret);
             qemu_aio_release(elem);
             goto restart;
         } else {
@@ -209,7 +216,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
     qemu_mutex_unlock(&lock);
 }
 
-static AIOPool thread_pool_cb_pool = {
+static const AIOCBInfo thread_pool_aiocb_info = {
     .aiocb_size         = sizeof(ThreadPoolElement),
     .cancel             = thread_pool_cancel,
 };
@@ -219,7 +226,7 @@ BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
 {
     ThreadPoolElement *req;
 
-    req = qemu_aio_get(&thread_pool_cb_pool, NULL, cb, opaque);
+    req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque);
     req->func = func;
     req->arg = arg;
     req->state = THREAD_QUEUED;