diff mbox

[v6,13/22] instrument: Support synchronous modification of vCPU state

Message ID 150529956916.10902.377591821566438337.stgit@frigg.lan (mailing list archive)
State New, archived
Headers show

Commit Message

Lluís Vilanova Sept. 13, 2017, 10:46 a.m. UTC
Stops all vCPUs to allow performing management operations like TB
invalidations. These are later necessary to ensure translated code does not
reference unloaded instrumentation libraries.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 instrument/control.c     |   67 ++++++++++++++++++++++++++++++++++++++++++++++
 instrument/control.h     |   26 ++++++++++++++++++
 instrument/control.inc.h |   11 ++++++++
 3 files changed, 104 insertions(+)
diff mbox

Patch

diff --git a/instrument/control.c b/instrument/control.c
index c4b3ca0440..4f9c138ccf 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,6 +13,7 @@ 
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "qemu/compiler.h"
+#include "qemu/main-loop.h"
 #include "qom/cpu.h"
 
 
@@ -40,6 +41,72 @@  void instr_cpu_remove(CPUState *vcpu)
 }
 
 
+static void instr_cpu_stop_all__cb(CPUState *cpu, run_on_cpu_data data)
+{
+    InstrCPUStop *info = data.host_ptr;
+    /* run posted function */
+    if (info->fun) {
+        info->fun(cpu, info->data);
+    }
+#if !defined(CONFIG_USER_ONLY)
+    /* signal we're out of the main vCPU loop */
+    unsigned int count = atomic_load_acquire(&info->count);
+    atomic_store_release(&info->count, count + 1);
+    atomic_store_release(&info->stopped, true);
+    /* wait until we're good to go again */
+    qemu_cond_wait(&info->cond, &info->mutex);
+    count = atomic_load_acquire(&info->count);
+    atomic_store_release(&info->count, count - 1);
+    qemu_mutex_unlock(&info->mutex);
+#endif
+}
+
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+                              instr_cpu_stop_fun fun, void *data)
+{
+    CPUState *cpu;
+
+    info->fun = fun;
+    info->data = data;
+
+#if !defined(CONFIG_USER_ONLY)
+    info->count = 0;
+    qemu_cond_init(&info->cond);
+    qemu_mutex_init(&info->mutex);
+
+    /* main dispatch loop and run_on_cpu() lock the BQL */
+    qemu_mutex_unlock_iothread();
+#endif
+
+    CPU_FOREACH(cpu) {
+#if !defined(CONFIG_USER_ONLY)
+        atomic_store_release(&info->stopped, false);
+        qemu_mutex_lock(&info->mutex);
+        async_run_on_cpu(cpu, instr_cpu_stop_all__cb,
+                         RUN_ON_CPU_HOST_PTR(info));
+        while (!atomic_load_acquire(&info->stopped)) {
+            /* wait for vCPU to signal it's stopped */
+        }
+#else
+        instr_cpu_stop_all__cb(cpu, RUN_ON_CPU_HOST_PTR(info));
+#endif
+    }
+}
+
+void instr_cpu_stop_all_end(InstrCPUStop *info)
+{
+#if !defined(CONFIG_USER_ONLY)
+    qemu_cond_broadcast(&info->cond);
+    while (atomic_load_acquire(&info->count)) {
+        /* wait for all vCPUs to continue before we can destroy info */
+    }
+    qemu_cond_destroy(&info->cond);
+    qemu_mutex_destroy(&info->mutex);
+    qemu_mutex_lock_iothread();
+#endif
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index 57cea07fa7..03e87b2b8f 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -46,6 +46,32 @@  static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
  */
 static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
 
+typedef struct InstrCPUStop InstrCPUStop;
+typedef void (*instr_cpu_stop_fun)(CPUState *cpu, void *data);
+
+/**
+ * instr_cpu_stop_all_begin:
+ * @info: Opaque structure describing the operation.
+ * @fun: Function to run on the context of each vCPU once stopped.
+ * @data: Pointer to pass to @fun.
+ *
+ * Ensure all vCPUs stop executing guest code, and execute @fun on their context
+ * in turn. Returns with all vCPUs still stopped.
+ *
+ * Assumes cpu_list_lock() and that the QBL is locked before calling.
+ */
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+                              instr_cpu_stop_fun fun, void *data);
+
+/**
+ * instr_cpu_stop_all_end:
+ * @info: Opaque structure passed to a previous instr_cpu_stop_all_begin()
+ *     call.
+ *
+ * Resume execution on all vCPUs stopped by instr_cpu_stop_all_begin().
+ */
+void instr_cpu_stop_all_end(InstrCPUStop *info);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 45daae7d1d..6d65b23ead 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -15,6 +15,17 @@ 
 #include <stdint.h>
 
 
+struct InstrCPUStop {
+    instr_cpu_stop_fun fun;
+    void *data;
+#if !defined(CONFIG_USER_ONLY)
+    bool stopped;
+    unsigned int count;
+    QemuCond cond;
+    QemuMutex mutex;
+#endif
+};
+
 extern unsigned int instr_cpus_count;
 extern CPUState **instr_cpus;