All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ilya Leoshkevich <iii@linux.ibm.com>
To: "Richard Henderson" <richard.henderson@linaro.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>
Cc: qemu-devel@nongnu.org, Ilya Leoshkevich <iii@linux.ibm.com>
Subject: [PATCH 16/18] cpu: Allow pausing and resuming CPUs in qemu-user
Date: Mon, 23 Sep 2024 18:13:11 +0200	[thread overview]
Message-ID: <20240923162208.90745-17-iii@linux.ibm.com> (raw)
In-Reply-To: <20240923162208.90745-1-iii@linux.ibm.com>

Move the respective functions from sysemu to cpu-common.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 accel/tcg/user-exec-stub.c |   4 --
 accel/tcg/user-exec.c      |  11 +++-
 cpu-common.c               | 115 +++++++++++++++++++++++++++++++++++++
 include/exec/cpu-common.h  |   7 +++
 include/sysemu/cpus.h      |   5 --
 system/cpus.c              | 108 ----------------------------------
 6 files changed, 132 insertions(+), 118 deletions(-)

diff --git a/accel/tcg/user-exec-stub.c b/accel/tcg/user-exec-stub.c
index 4fbe2dbdc88..e79f2e88498 100644
--- a/accel/tcg/user-exec-stub.c
+++ b/accel/tcg/user-exec-stub.c
@@ -2,10 +2,6 @@
 #include "hw/core/cpu.h"
 #include "exec/replay-core.h"
 
-void cpu_resume(CPUState *cpu)
-{
-}
-
 void cpu_remove_sync(CPUState *cpu)
 {
 }
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index de4753cded7..3399b074485 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -1293,12 +1293,19 @@ int cpu_exec_user(CPUState *cs)
 {
     int trapnr;
 
+    do {
+        qemu_wait_io_event(cs);
+    } while (!cpu_can_run(cs));
+
     bql_unlock();
     cpu_exec_start(cs);
     trapnr = cpu_exec(cs);
     cpu_exec_end(cs);
     bql_lock();
-    process_queued_cpu_work(cs);
+
+    do {
+        qemu_wait_io_event(cs);
+    } while (!cpu_can_run(cs));
 
     return trapnr;
 }
@@ -1306,11 +1313,13 @@ int cpu_exec_user(CPUState *cs)
 void qemu_cpu_kick(CPUState *cpu)
 {
     cpu_exit(cpu);
+    qemu_cond_broadcast(cpu->halt_cond);
 }
 
 void cpu_enter_syscall(CPUState *cs)
 {
     cs->in_syscall = true;
+    qemu_pause_cond_broadcast();
 }
 
 void cpu_exit_syscall(CPUState *cs)
diff --git a/cpu-common.c b/cpu-common.c
index 2822ee9373d..979e3fe8806 100644
--- a/cpu-common.c
+++ b/cpu-common.c
@@ -24,6 +24,8 @@
 #include "sysemu/cpus.h"
 #include "qemu/lockable.h"
 #include "trace/trace-root.h"
+#include "exec/replay-core.h"
+#include "qemu/plugin.h"
 
 QemuMutex qemu_cpu_list_lock;
 static QemuCond exclusive_cond;
@@ -456,6 +458,9 @@ void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
 /* The Big QEMU Lock (BQL) */
 static QemuMutex bql = QEMU_MUTEX_INITIALIZER;
 
+/* system init */
+static QemuCond qemu_pause_cond = QEMU_COND_INITIALIZER;
+
 QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
 
 bool bql_locked(void)
@@ -498,6 +503,105 @@ void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
     do_run_on_cpu(cpu, func, data, &bql);
 }
 
+static bool all_vcpus_paused(void)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        if (!cpu_is_paused(cpu)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void pause_all_vcpus(void)
+{
+    CPUState *cpu;
+
+    qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
+    CPU_FOREACH(cpu) {
+        cpu_pause(cpu);
+    }
+
+    /* We need to drop the replay_lock so any vCPU threads woken up
+     * can finish their replay tasks
+     */
+    replay_mutex_unlock();
+
+    while (!all_vcpus_paused()) {
+        qemu_cond_wait_bql(&qemu_pause_cond);
+        CPU_FOREACH(cpu) {
+            qemu_cpu_kick(cpu);
+        }
+    }
+
+    bql_unlock();
+    replay_mutex_lock();
+    bql_lock();
+}
+
+void qemu_pause_cond_broadcast(void)
+{
+    qemu_cond_broadcast(&qemu_pause_cond);
+}
+
+static void qemu_cpu_stop(CPUState *cpu, bool exit)
+{
+    g_assert(qemu_cpu_is_self(cpu));
+    cpu->stop = false;
+    cpu->stopped = true;
+    if (exit) {
+        cpu_exit(cpu);
+    }
+    qemu_pause_cond_broadcast();
+}
+
+void qemu_wait_io_event_common(CPUState *cpu)
+{
+    qatomic_set_mb(&cpu->thread_kicked, false);
+    if (cpu->stop) {
+        qemu_cpu_stop(cpu, false);
+    }
+    process_queued_cpu_work(cpu);
+}
+
+void qemu_wait_io_event(CPUState *cpu)
+{
+    bool slept = false;
+
+    while (cpu_thread_is_idle(cpu)) {
+        if (!slept) {
+            slept = true;
+            qemu_plugin_vcpu_idle_cb(cpu);
+        }
+        qemu_cond_wait_bql(cpu->halt_cond);
+    }
+    if (slept) {
+        qemu_plugin_vcpu_resume_cb(cpu);
+    }
+
+    qemu_wait_io_event_common(cpu);
+}
+
+void cpu_pause(CPUState *cpu)
+{
+    if (qemu_cpu_is_self(cpu)) {
+        qemu_cpu_stop(cpu, true);
+    } else {
+        cpu->stop = true;
+        qemu_cpu_kick(cpu);
+    }
+}
+
+void cpu_resume(CPUState *cpu)
+{
+    cpu->stop = false;
+    cpu->stopped = false;
+    qemu_cpu_kick(cpu);
+}
+
 bool cpu_work_list_empty(CPUState *cpu)
 {
     return QSIMPLEQ_EMPTY_ATOMIC(&cpu->work_list);
@@ -516,3 +620,14 @@ int cpu_thread_is_idle_common(CPUState *cpu)
     }
     return -1;
 }
+
+bool cpu_can_run(CPUState *cpu)
+{
+    if (cpu->stop) {
+        return false;
+    }
+    if (cpu_is_stopped(cpu)) {
+        return false;
+    }
+    return true;
+}
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index e8b530ed889..a54368c5b69 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -234,6 +234,13 @@ void cpu_exit_syscall(CPUState *cs);
 int cpu_thread_is_idle_common(CPUState *cpu);
 bool cpu_thread_is_idle(CPUState *cpu);
 bool cpu_is_paused(CPUState *cpu);
+bool cpu_can_run(CPUState *cpu);
+void qemu_wait_io_event_common(CPUState *cpu);
+void qemu_wait_io_event(CPUState *cpu);
+void pause_all_vcpus(void);
+void qemu_pause_cond_broadcast(void);
+bool cpu_work_list_empty(CPUState *cpu);
+
 
 /**
  * env_archcpu(env)
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index bfa3fd45650..ebfd0b77bcd 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -20,11 +20,7 @@ void dummy_start_vcpu_thread(CPUState *);
 #define VCPU_THREAD_NAME_SIZE 16
 
 void cpus_kick_thread(CPUState *cpu);
-bool cpu_work_list_empty(CPUState *cpu);
 bool all_cpu_threads_idle(void);
-bool cpu_can_run(CPUState *cpu);
-void qemu_wait_io_event_common(CPUState *cpu);
-void qemu_wait_io_event(CPUState *cpu);
 void cpu_thread_signal_created(CPUState *cpu);
 void cpu_thread_signal_destroyed(CPUState *cpu);
 void cpu_handle_guest_debug(CPUState *cpu);
@@ -34,7 +30,6 @@ void cpu_handle_guest_debug(CPUState *cpu);
 bool qemu_in_vcpu_thread(void);
 void qemu_init_cpu_loop(void);
 void resume_all_vcpus(void);
-void pause_all_vcpus(void);
 void cpu_stop_current(void);
 
 extern int icount_align_option;
diff --git a/system/cpus.c b/system/cpus.c
index 407140c41f6..9ad7bae056e 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -307,17 +307,6 @@ int vm_shutdown(void)
     return do_vm_stop(RUN_STATE_SHUTDOWN, false);
 }
 
-bool cpu_can_run(CPUState *cpu)
-{
-    if (cpu->stop) {
-        return false;
-    }
-    if (cpu_is_stopped(cpu)) {
-        return false;
-    }
-    return true;
-}
-
 void cpu_handle_guest_debug(CPUState *cpu)
 {
     if (replay_running_debug()) {
@@ -400,56 +389,15 @@ static QemuThread io_thread;
 
 /* cpu creation */
 static QemuCond qemu_cpu_cond;
-/* system init */
-static QemuCond qemu_pause_cond;
 
 void qemu_init_cpu_loop(void)
 {
     qemu_init_sigbus();
     qemu_cond_init(&qemu_cpu_cond);
-    qemu_cond_init(&qemu_pause_cond);
 
     qemu_thread_get_self(&io_thread);
 }
 
-static void qemu_cpu_stop(CPUState *cpu, bool exit)
-{
-    g_assert(qemu_cpu_is_self(cpu));
-    cpu->stop = false;
-    cpu->stopped = true;
-    if (exit) {
-        cpu_exit(cpu);
-    }
-    qemu_cond_broadcast(&qemu_pause_cond);
-}
-
-void qemu_wait_io_event_common(CPUState *cpu)
-{
-    qatomic_set_mb(&cpu->thread_kicked, false);
-    if (cpu->stop) {
-        qemu_cpu_stop(cpu, false);
-    }
-    process_queued_cpu_work(cpu);
-}
-
-void qemu_wait_io_event(CPUState *cpu)
-{
-    bool slept = false;
-
-    while (cpu_thread_is_idle(cpu)) {
-        if (!slept) {
-            slept = true;
-            qemu_plugin_vcpu_idle_cb(cpu);
-        }
-        qemu_cond_wait_bql(cpu->halt_cond);
-    }
-    if (slept) {
-        qemu_plugin_vcpu_resume_cb(cpu);
-    }
-
-    qemu_wait_io_event_common(cpu);
-}
-
 void cpus_kick_thread(CPUState *cpu)
 {
     if (cpu->thread_kicked) {
@@ -513,67 +461,11 @@ void cpu_thread_signal_destroyed(CPUState *cpu)
     qemu_cond_signal(&qemu_cpu_cond);
 }
 
-void cpu_pause(CPUState *cpu)
-{
-    if (qemu_cpu_is_self(cpu)) {
-        qemu_cpu_stop(cpu, true);
-    } else {
-        cpu->stop = true;
-        qemu_cpu_kick(cpu);
-    }
-}
-
-void cpu_resume(CPUState *cpu)
-{
-    cpu->stop = false;
-    cpu->stopped = false;
-    qemu_cpu_kick(cpu);
-}
-
 bool cpu_is_paused(CPUState *cpu)
 {
     return cpu->stopped;
 }
 
-static bool all_vcpus_paused(void)
-{
-    CPUState *cpu;
-
-    CPU_FOREACH(cpu) {
-        if (!cpu_is_paused(cpu)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-void pause_all_vcpus(void)
-{
-    CPUState *cpu;
-
-    qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
-    CPU_FOREACH(cpu) {
-        cpu_pause(cpu);
-    }
-
-    /* We need to drop the replay_lock so any vCPU threads woken up
-     * can finish their replay tasks
-     */
-    replay_mutex_unlock();
-
-    while (!all_vcpus_paused()) {
-        qemu_cond_wait_bql(&qemu_pause_cond);
-        CPU_FOREACH(cpu) {
-            qemu_cpu_kick(cpu);
-        }
-    }
-
-    bql_unlock();
-    replay_mutex_lock();
-    bql_lock();
-}
-
 void resume_all_vcpus(void)
 {
     CPUState *cpu;
-- 
2.46.0



  parent reply	other threads:[~2024-09-23 16:29 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-23 16:12 [PATCH 00/18] Stop all qemu-cpu threads on a breakpoint Ilya Leoshkevich
2024-09-23 16:12 ` [PATCH 01/18] gdbstub: Make gdb_get_char() static Ilya Leoshkevich
2024-10-05 19:20   ` Richard Henderson
2024-09-23 16:12 ` [PATCH 02/18] gdbstub: Move phy_memory_mode to GDBSystemState Ilya Leoshkevich
2024-10-05 19:21   ` Richard Henderson
2024-09-23 16:12 ` [PATCH 03/18] gdbstub: Move gdb_syscall_mode to GDBSyscallState Ilya Leoshkevich
2024-10-05 19:22   ` Richard Henderson
2024-09-23 16:12 ` [PATCH 04/18] gdbstub: Factor out gdb_try_stop() Ilya Leoshkevich
2024-10-05 19:26   ` Richard Henderson
2024-09-23 16:13 ` [PATCH 05/18] accel/tcg: Factor out cpu_exec_user() Ilya Leoshkevich
2024-10-05 19:29   ` Richard Henderson
2024-09-23 16:13 ` [PATCH 06/18] qemu-thread: Introduce QEMU_MUTEX_INITIALIZER Ilya Leoshkevich
2024-10-05 19:30   ` Richard Henderson
2024-09-23 16:13 ` [PATCH 07/18] qemu-thread: Introduce QEMU_COND_INITIALIZER Ilya Leoshkevich
2024-10-05 19:30   ` Richard Henderson
2024-09-23 16:13 ` [PATCH 08/18] replay: Add replay_mutex_{lock, unlock}() stubs for qemu-user Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 09/18] qemu-timer: Provide qemu_clock_enable() stub " Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 10/18] cpu: Use BQL in qemu-user Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 11/18] accel/tcg: Unify user implementations of qemu_cpu_kick() Ilya Leoshkevich
2024-10-05 19:31   ` Richard Henderson
2024-09-23 16:13 ` [PATCH 12/18] cpu: Track CPUs executing syscalls Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 13/18] cpu: Implement cpu_thread_is_idle() for qemu-user Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 14/18] cpu: Introduce cpu_is_paused() Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 15/18] cpu: Set current_cpu early in qemu-user Ilya Leoshkevich
2024-09-23 16:13 ` Ilya Leoshkevich [this message]
2024-09-23 16:13 ` [PATCH 17/18] gdbstub: Pause all CPUs before sending stop replies Ilya Leoshkevich
2024-09-23 16:13 ` [PATCH 18/18] tests/tcg: Stress test thread breakpoints Ilya Leoshkevich
2024-09-23 16:37 ` [PATCH 00/18] Stop all qemu-cpu threads on a breakpoint Ilya Leoshkevich
2024-09-24 11:46 ` Richard Henderson
2024-09-25  7:43   ` Ilya Leoshkevich
2024-10-05 19:51     ` Richard Henderson
2024-10-05 20:26       ` Ilya Leoshkevich
2024-10-05 20:35         ` Ilya Leoshkevich
2024-10-08 18:17           ` Richard Henderson
2024-10-09 22:01             ` Ilya Leoshkevich
2025-01-08 15:56 ` Alex Bennée
2025-01-08 16:20   ` Ilya Leoshkevich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240923162208.90745-17-iii@linux.ibm.com \
    --to=iii@linux.ibm.com \
    --cc=alex.bennee@linaro.org \
    --cc=pbonzini@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.