summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-10-31 10:09:11 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2012-10-31 10:38:01 +0100
commit19d092cf9ba3c01b0e22ef65c499ae7ddc28d0e8 (patch)
tree42531fcfcc0eebe598a900a8f0d9e5b289808abb
parentd354c7eccf5466ec2715a03d3f33dbfd6680dcc5 (diff)
downloadqemu-19d092cf9ba3c01b0e22ef65c499ae7ddc28d0e8.zip
threadpool: do not take lock in event_notifier_ready
The ordering is: worker thread consumer thread ------------------------------------------------------------------- write ret event_notifier_test_and_clear wmb() read state write state rmb() event_notifier_set read ret Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--thread-pool.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/thread-pool.c b/thread-pool.c
index 80749b77e0..651b32419b 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -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 {