[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v4 09/12] linux-user: Support CPU work queue
From: |
Sergey Fedorov |
Subject: |
[Qemu-devel] [PATCH v4 09/12] linux-user: Support CPU work queue |
Date: |
Fri, 15 Jul 2016 21:57:23 +0300 |
From: Sergey Fedorov <address@hidden>
Make CPU work core functions common between system and user-mode
emulation. User-mode does not have BQL, so process_queued_cpu_work() is
protected by 'exclusive_lock'.
Signed-off-by: Sergey Fedorov <address@hidden>
Signed-off-by: Sergey Fedorov <address@hidden>
Reviewed-by: Alex Bennée <address@hidden>
---
Changes in v2:
- 'qemu_work_cond' definition moved to cpu-exec-common.c
- documentation commend for new public API added
---
cpu-exec-common.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
cpus.c | 86 +------------------------------------------------
include/exec/exec-all.h | 17 ++++++++++
linux-user/main.c | 8 +++++
4 files changed, 111 insertions(+), 85 deletions(-)
diff --git a/cpu-exec-common.c b/cpu-exec-common.c
index 0cb4ae60eff9..a233f0124559 100644
--- a/cpu-exec-common.c
+++ b/cpu-exec-common.c
@@ -77,3 +77,88 @@ void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
}
siglongjmp(cpu->jmp_env, 1);
}
+
+QemuCond qemu_work_cond;
+
+static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
+{
+ qemu_mutex_lock(&cpu->work_mutex);
+ if (cpu->queued_work_first == NULL) {
+ cpu->queued_work_first = wi;
+ } else {
+ cpu->queued_work_last->next = wi;
+ }
+ cpu->queued_work_last = wi;
+ wi->next = NULL;
+ wi->done = false;
+ qemu_mutex_unlock(&cpu->work_mutex);
+
+ qemu_cpu_kick(cpu);
+}
+
+void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+{
+ struct qemu_work_item wi;
+
+ if (qemu_cpu_is_self(cpu)) {
+ func(cpu, data);
+ return;
+ }
+
+ wi.func = func;
+ wi.data = data;
+ wi.free = false;
+
+ queue_work_on_cpu(cpu, &wi);
+ while (!atomic_mb_read(&wi.done)) {
+ CPUState *self_cpu = current_cpu;
+
+ qemu_cond_wait(&qemu_work_cond, qemu_get_cpu_work_mutex());
+ current_cpu = self_cpu;
+ }
+}
+
+void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+{
+ struct qemu_work_item *wi;
+
+ if (qemu_cpu_is_self(cpu)) {
+ func(cpu, data);
+ return;
+ }
+
+ wi = g_malloc0(sizeof(struct qemu_work_item));
+ wi->func = func;
+ wi->data = data;
+ wi->free = true;
+
+ queue_work_on_cpu(cpu, wi);
+}
+
+void process_queued_cpu_work(CPUState *cpu)
+{
+ struct qemu_work_item *wi;
+
+ if (cpu->queued_work_first == NULL) {
+ return;
+ }
+
+ 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(cpu, wi->data);
+ qemu_mutex_lock(&cpu->work_mutex);
+ if (wi->free) {
+ g_free(wi);
+ } else {
+ atomic_mb_set(&wi->done, true);
+ }
+ }
+ qemu_mutex_unlock(&cpu->work_mutex);
+ qemu_cond_broadcast(&qemu_work_cond);
+}
diff --git a/cpus.c b/cpus.c
index 51fd8c18b4c8..282d7e399902 100644
--- a/cpus.c
+++ b/cpus.c
@@ -896,7 +896,6 @@ static QemuThread io_thread;
static QemuCond qemu_cpu_cond;
/* system init */
static QemuCond qemu_pause_cond;
-static QemuCond qemu_work_cond;
void qemu_init_cpu_loop(void)
{
@@ -910,66 +909,11 @@ void qemu_init_cpu_loop(void)
qemu_thread_get_self(&io_thread);
}
-static QemuMutex *qemu_get_cpu_work_mutex(void)
+QemuMutex *qemu_get_cpu_work_mutex(void)
{
return &qemu_global_mutex;
}
-static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
-{
- qemu_mutex_lock(&cpu->work_mutex);
- if (cpu->queued_work_first == NULL) {
- cpu->queued_work_first = wi;
- } else {
- cpu->queued_work_last->next = wi;
- }
- cpu->queued_work_last = wi;
- wi->next = NULL;
- wi->done = false;
- qemu_mutex_unlock(&cpu->work_mutex);
-
- qemu_cpu_kick(cpu);
-}
-
-void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
-{
- struct qemu_work_item wi;
-
- if (qemu_cpu_is_self(cpu)) {
- func(cpu, data);
- return;
- }
-
- wi.func = func;
- wi.data = data;
- wi.free = false;
-
- queue_work_on_cpu(cpu, &wi);
- while (!atomic_mb_read(&wi.done)) {
- CPUState *self_cpu = current_cpu;
-
- qemu_cond_wait(&qemu_work_cond, qemu_get_cpu_work_mutex());
- current_cpu = self_cpu;
- }
-}
-
-void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
-{
- struct qemu_work_item *wi;
-
- if (qemu_cpu_is_self(cpu)) {
- func(cpu, data);
- return;
- }
-
- wi = g_malloc0(sizeof(struct qemu_work_item));
- wi->func = func;
- wi->data = data;
- wi->free = true;
-
- queue_work_on_cpu(cpu, wi);
-}
-
static void qemu_kvm_destroy_vcpu(CPUState *cpu)
{
if (kvm_destroy_vcpu(cpu) < 0) {
@@ -982,34 +926,6 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu)
{
}
-static void process_queued_cpu_work(CPUState *cpu)
-{
- struct qemu_work_item *wi;
-
- if (cpu->queued_work_first == NULL) {
- return;
- }
-
- 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(cpu, wi->data);
- qemu_mutex_lock(&cpu->work_mutex);
- if (wi->free) {
- g_free(wi);
- } else {
- atomic_mb_set(&wi->done, true);
- }
- }
- qemu_mutex_unlock(&cpu->work_mutex);
- qemu_cond_broadcast(&qemu_work_cond);
-}
-
static void qemu_wait_io_event_common(CPUState *cpu)
{
if (cpu->stop) {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index acda7b613d53..8d5c7dbcf5a9 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -407,4 +407,21 @@ extern int singlestep;
extern CPUState *tcg_current_cpu;
extern bool exit_request;
+/**
+ * qemu_work_cond - condition to wait for CPU work items completion
+ */
+extern QemuCond qemu_work_cond;
+
+/**
+ * qemu_get_cpu_work_mutex() - get the mutex which protects CPU work execution
+ *
+ * Return: A pointer to the mutex.
+ */
+QemuMutex *qemu_get_cpu_work_mutex(void);
+/**
+ * process_queued_cpu_work() - process all items on CPU work queue
+ * @cpu: The CPU which work queue to process.
+ */
+void process_queued_cpu_work(CPUState *cpu);
+
#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index a8790ac63f68..fce61d5a35fc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -121,6 +121,7 @@ void qemu_init_cpu_loop(void)
qemu_mutex_init(&exclusive_lock);
qemu_cond_init(&exclusive_cond);
qemu_cond_init(&exclusive_resume);
+ qemu_cond_init(&qemu_work_cond);
}
/* Make sure everything is in a consistent state for calling fork(). */
@@ -149,6 +150,7 @@ void fork_end(int child)
qemu_mutex_init(&cpu_list_mutex);
qemu_cond_init(&exclusive_cond);
qemu_cond_init(&exclusive_resume);
+ qemu_cond_init(&qemu_work_cond);
qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock);
gdbserver_fork(thread_cpu);
} else {
@@ -157,6 +159,11 @@ void fork_end(int child)
}
}
+QemuMutex *qemu_get_cpu_work_mutex(void)
+{
+ return &exclusive_lock;
+}
+
/* Wait for pending exclusive operations to complete. The exclusive lock
must be held. */
static inline void exclusive_idle(void)
@@ -215,6 +222,7 @@ static inline void cpu_exec_end(CPUState *cpu)
qemu_cond_signal(&exclusive_cond);
}
exclusive_idle();
+ process_queued_cpu_work(cpu);
qemu_mutex_unlock(&exclusive_lock);
}
--
2.9.1
- [Qemu-devel] [PATCH v4 11/12] cpu-exec-common: Introduce async_safe_run_on_cpu(), (continued)
- [Qemu-devel] [PATCH v4 11/12] cpu-exec-common: Introduce async_safe_run_on_cpu(), Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 10/12] bsd-user: Support CPU work queue, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 05/12] cpus: Rename flush_queued_work(), Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 06/12] linux-user: Use QemuMutex and QemuCond, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 02/12] cpus: pass CPUState to run_on_cpu helpers, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 08/12] linux-user: Add qemu_cpu_is_self() and qemu_cpu_kick(), Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 03/12] cpus: Move common code out of {async_, }run_on_cpu(), Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 12/12] tcg: Make tb_flush() thread safe, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 04/12] cpus: Wrap mutex used to protect CPU work, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 07/12] linux-user: Rework exclusive operation mechanism, Sergey Fedorov, 2016/07/15
- [Qemu-devel] [PATCH v4 09/12] linux-user: Support CPU work queue,
Sergey Fedorov <=