[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH V6 13/18] cpu: introduce async_run_safe_work_on_
From: |
fred . konrad |
Subject: |
[Qemu-devel] [RFC PATCH V6 13/18] cpu: introduce async_run_safe_work_on_cpu. |
Date: |
Fri, 26 Jun 2015 16:47:28 +0200 |
From: KONRAD Frederic <address@hidden>
We already had async_run_on_cpu but we need all VCPUs outside their execution
loop to execute some tb_flush/invalidate task:
async_run_on_cpu_safe schedule a work on a VCPU but the work start when no more
VCPUs are executing code.
When a safe work is pending cpu_has_work returns true, so cpu_exec returns and
the VCPUs can't enters execution loop. cpu_thread_is_idle returns false so at
the moment where all VCPUs are stop || stopped the safe work queue can be
flushed.
Signed-off-by: KONRAD Frederic <address@hidden>
---
cpu-exec.c | 5 ++++
cpus.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
include/qom/cpu.h | 21 +++++++++++++++++
3 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/cpu-exec.c b/cpu-exec.c
index de256d6..d6442cd 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -382,6 +382,11 @@ int cpu_exec(CPUArchState *env)
volatile bool have_tb_lock = false;
#endif
+ if (async_safe_work_pending()) {
+ cpu->exit_request = 1;
+ return 0;
+ }
+
if (cpu->halted) {
if (!cpu_has_work(cpu)) {
return EXCP_HALTED;
diff --git a/cpus.c b/cpus.c
index 5f13d73..aee445a 100644
--- a/cpus.c
+++ b/cpus.c
@@ -75,7 +75,7 @@ bool cpu_is_stopped(CPUState *cpu)
bool cpu_thread_is_idle(CPUState *cpu)
{
- if (cpu->stop || cpu->queued_work_first) {
+ if (cpu->stop || cpu->queued_work_first || cpu->queued_safe_work_first) {
return false;
}
if (cpu_is_stopped(cpu)) {
@@ -892,6 +892,69 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void
*data), void *data)
qemu_cpu_kick(cpu);
}
+void async_run_safe_work_on_cpu(CPUState *cpu, void (*func)(void *data),
+ void *data)
+{
+ struct qemu_work_item *wi;
+
+ wi = g_malloc0(sizeof(struct qemu_work_item));
+ wi->func = func;
+ wi->data = data;
+ wi->free = true;
+ if (cpu->queued_safe_work_first == NULL) {
+ cpu->queued_safe_work_first = wi;
+ } else {
+ cpu->queued_safe_work_last->next = wi;
+ }
+ cpu->queued_safe_work_last = wi;
+ wi->next = NULL;
+ wi->done = false;
+
+ CPU_FOREACH(cpu) {
+ qemu_cpu_kick_thread(cpu);
+ }
+}
+
+static void flush_queued_safe_work(CPUState *cpu)
+{
+ struct qemu_work_item *wi;
+ CPUState *other_cpu;
+
+ if (cpu->queued_safe_work_first == NULL) {
+ return;
+ }
+
+ CPU_FOREACH(other_cpu) {
+ if (other_cpu->tcg_executing != 0) {
+ return;
+ }
+ }
+
+ while ((wi = cpu->queued_safe_work_first)) {
+ cpu->queued_safe_work_first = wi->next;
+ wi->func(wi->data);
+ wi->done = true;
+ if (wi->free) {
+ g_free(wi);
+ }
+ }
+ cpu->queued_safe_work_last = NULL;
+ qemu_cond_broadcast(&qemu_work_cond);
+}
+
+bool async_safe_work_pending(void)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ if (cpu->queued_safe_work_first) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void flush_queued_work(CPUState *cpu)
{
struct qemu_work_item *wi;
@@ -919,6 +982,9 @@ static void qemu_wait_io_event_common(CPUState *cpu)
cpu->stopped = true;
qemu_cond_signal(&qemu_pause_cond);
}
+ qemu_mutex_unlock_iothread();
+ flush_queued_safe_work(cpu);
+ qemu_mutex_lock_iothread();
flush_queued_work(cpu);
cpu->thread_kicked = false;
}
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 1464afa..8f3fe56 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -260,6 +260,7 @@ struct CPUState {
bool running;
struct QemuCond *halt_cond;
struct qemu_work_item *queued_work_first, *queued_work_last;
+ struct qemu_work_item *queued_safe_work_first, *queued_safe_work_last;
bool thread_kicked;
bool created;
bool stop;
@@ -548,6 +549,26 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data),
void *data);
void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
/**
+ * async_run_safe_work_on_cpu:
+ * @cpu: The vCPU to run on.
+ * @func: The function to be executed.
+ * @data: Data to pass to the function.
+ *
+ * Schedules the function @func for execution on the vCPU @cpu asynchronously
+ * when all the VCPUs are outside their loop.
+ */
+void async_run_safe_work_on_cpu(CPUState *cpu, void (*func)(void *data),
+ void *data);
+
+/**
+ * async_safe_work_pending:
+ *
+ * Check whether any safe work is pending on any VCPUs.
+ * Returns: @true if a safe work is pending, @false otherwise.
+ */
+bool async_safe_work_pending(void);
+
+/**
* qemu_get_cpu:
* @index: The address@hidden value of the CPU to obtain.
*
--
1.9.0
- Re: [Qemu-devel] [RFC PATCH V6 07/18] Drop global lock during TCG code execution, (continued)
[Qemu-devel] [RFC PATCH V6 12/18] Use atomic cmpxchg to atomically check the exclusive value in a STREX, fred . konrad, 2015/06/26
[Qemu-devel] [RFC PATCH V6 14/18] add a callback when tb_invalidate is called., fred . konrad, 2015/06/26
[Qemu-devel] [RFC PATCH V6 16/18] arm: use tlb_flush*_all, fred . konrad, 2015/06/26
[Qemu-devel] [RFC PATCH V6 13/18] cpu: introduce async_run_safe_work_on_cpu.,
fred . konrad <=
[Qemu-devel] [RFC PATCH V6 15/18] cpu: introduce tlb_flush*_all., fred . konrad, 2015/06/26