summary refs log tree commit diff stats
path: root/cpus.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2015-07-10 12:32:32 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2015-09-09 15:34:55 +0200
commit376692b9dc6f02303ee07a4146d08d8727d79c0c (patch)
tree4e67dcac05713579e92b0a38935165e3cd2fd4e7 /cpus.c
parent0c71d41e2aa3c7356500ae624166f3bb8c201aee (diff)
downloadfocaccia-qemu-376692b9dc6f02303ee07a4146d08d8727d79c0c.tar.gz
focaccia-qemu-376692b9dc6f02303ee07a4146d08d8727d79c0c.zip
cpus: protect work list with work_mutex
Protect the list of queued work items with something other than
the BQL, as a preparation for running the work items outside it.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'cpus.c')
-rw-r--r--cpus.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/cpus.c b/cpus.c
index 4f3374e201..ea3ffdb900 100644
--- a/cpus.c
+++ b/cpus.c
@@ -819,6 +819,8 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
     wi.func = func;
     wi.data = data;
     wi.free = false;
+
+    qemu_mutex_lock(&cpu->work_mutex);
     if (cpu->queued_work_first == NULL) {
         cpu->queued_work_first = &wi;
     } else {
@@ -827,9 +829,10 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
     cpu->queued_work_last = &wi;
     wi.next = NULL;
     wi.done = false;
+    qemu_mutex_unlock(&cpu->work_mutex);
 
     qemu_cpu_kick(cpu);
-    while (!wi.done) {
+    while (!atomic_mb_read(&wi.done)) {
         CPUState *self_cpu = current_cpu;
 
         qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
@@ -850,6 +853,8 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
     wi->func = func;
     wi->data = data;
     wi->free = true;
+
+    qemu_mutex_lock(&cpu->work_mutex);
     if (cpu->queued_work_first == NULL) {
         cpu->queued_work_first = wi;
     } else {
@@ -858,6 +863,7 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
     cpu->queued_work_last = wi;
     wi->next = NULL;
     wi->done = false;
+    qemu_mutex_unlock(&cpu->work_mutex);
 
     qemu_cpu_kick(cpu);
 }
@@ -870,15 +876,23 @@ static void flush_queued_work(CPUState *cpu)
         return;
     }
 
-    while ((wi = cpu->queued_work_first)) {
+    qemu_mutex_lock(&cpu->work_mutex);
+    while (cpu->queued_work_first != NULL) {
+        wi = cpu->queued_work_first;
         cpu->queued_work_first = wi->next;
+        if (!cpu->queued_work_first) {
+            cpu->queued_work_last = NULL;
+        }
+        qemu_mutex_unlock(&cpu->work_mutex);
         wi->func(wi->data);
-        wi->done = true;
+        qemu_mutex_lock(&cpu->work_mutex);
         if (wi->free) {
             g_free(wi);
+        } else {
+            atomic_mb_set(&wi->done, true);
         }
     }
-    cpu->queued_work_last = NULL;
+    qemu_mutex_unlock(&cpu->work_mutex);
     qemu_cond_broadcast(&qemu_work_cond);
 }