Currently BQL is stubbed out in qemu-user. However, enabling the ability to pause and resume CPUs requires BQL, so introduce it.
Signed-off-by: Ilya Leoshkevich <i...@linux.ibm.com> --- accel/tcg/user-exec.c | 2 ++ bsd-user/freebsd/os-syscall.c | 6 ++++ bsd-user/main.c | 2 ++ cpu-common.c | 45 ++++++++++++++++++++++++++++++ gdbstub/user.c | 5 ++++ linux-user/main.c | 3 ++ linux-user/syscall.c | 6 ++++ system/cpus.c | 52 ++--------------------------------- 8 files changed, 72 insertions(+), 49 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index ca3e8e988ee..d56882c87f3 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1293,9 +1293,11 @@ int cpu_exec_user(CPUState *cs) { int trapnr; + bql_unlock(); cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + bql_lock(); process_queued_cpu_work(cs); return trapnr; diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index ca2f6fdb66e..c2849d43223 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -32,6 +32,7 @@ #include "qemu.h" #include "signal-common.h" #include "user/syscall-trace.h" +#include "qemu/main-loop.h" /* BSD independent syscall shims */ #include "bsd-file.h" @@ -935,16 +936,21 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, { abi_long ret; + bql_unlock(); + if (do_strace) { print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); } ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + if (do_strace) { print_freebsd_syscall_ret(num, ret); } + bql_lock(); + return ret; } diff --git a/bsd-user/main.c b/bsd-user/main.c index cc980e6f401..ba5b54c228d 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -48,6 +48,7 @@ #include "qemu/guest-random.h" #include "gdbstub/user.h" #include "exec/page-vary.h" +#include "qemu/main-loop.h" #include "host-os.h" #include "target_arch_cpu.h" @@ -616,6 +617,7 @@ int main(int argc, char **argv) target_cpu_init(env, regs); + bql_lock(); if (gdbstub) { gdbserver_start(gdbstub); gdb_handlesig(cpu, 0, NULL, NULL, 0); diff --git a/cpu-common.c b/cpu-common.c index 6b262233a3b..cb7c10a3915 100644 --- a/cpu-common.c +++ b/cpu-common.c @@ -452,3 +452,48 @@ void cpu_breakpoint_remove_all(CPUState *cpu, int mask) } } } + +/* The Big QEMU Lock (BQL) */ +static QemuMutex bql = QEMU_MUTEX_INITIALIZER; + +QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked) + +bool bql_locked(void) +{ + return get_bql_locked(); +} + +/* + * The BQL is taken from so many places that it is worth profiling the + * callers directly, instead of funneling them all through a single function. + */ +void bql_lock_impl(const char *file, int line) +{ + QemuMutexLockFunc bql_lock_fn = qatomic_read(&bql_mutex_lock_func); + + g_assert(!bql_locked()); + bql_lock_fn(&bql, file, line); + set_bql_locked(true); +} + +void bql_unlock(void) +{ + g_assert(bql_locked()); + set_bql_locked(false); + qemu_mutex_unlock(&bql); +} + +void qemu_cond_wait_bql(QemuCond *cond) +{ + qemu_cond_wait(cond, &bql); +} + +void qemu_cond_timedwait_bql(QemuCond *cond, int ms) +{ + qemu_cond_timedwait(cond, &bql, ms); +} + +void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data) +{ + do_run_on_cpu(cpu, func, data, &bql); +} diff --git a/gdbstub/user.c b/gdbstub/user.c index 77ba227fc3b..82007b09db6 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" #include "qemu/cutils.h" +#include "qemu/main-loop.h" #include "qemu/sockets.h" #include "exec/hwaddr.h" #include "exec/tb-flush.h" @@ -169,6 +170,8 @@ void gdb_exit(int code) { char buf[4]; + BQL_LOCK_GUARD(); + if (!gdbserver_state.init) { return; } @@ -464,6 +467,8 @@ void gdbserver_fork_end(CPUState *cpu, pid_t pid) char b; int fd; + BQL_LOCK_GUARD(); + if (!gdbserver_state.init || gdbserver_user_state.fd < 0) { return; } diff --git a/linux-user/main.c b/linux-user/main.c index 8143a0d4b02..016f60bf3dc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -57,6 +57,7 @@ #include "user-mmap.h" #include "tcg/perf.h" #include "exec/page-vary.h" +#include "qemu/main-loop.h" #ifdef CONFIG_SEMIHOSTING #include "semihosting/semihost.h" @@ -1011,6 +1012,8 @@ int main(int argc, char **argv, char **envp) target_cpu_copy_regs(env, regs); + bql_lock(); + if (gdbstub) { if (gdbserver_start(gdbstub) < 0) { fprintf(stderr, "qemu: could not open gdbserver on %s\n", diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b693aeff5bb..ff34ae11340 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -144,6 +144,7 @@ #include "qapi/error.h" #include "fd-trans.h" #include "cpu_loop-common.h" +#include "qemu/main-loop.h" #ifndef CLONE_IO #define CLONE_IO 0x80000000 /* Clone io context */ @@ -6529,6 +6530,7 @@ static void *clone_func(void *arg) /* Wait until the parent has finished initializing the tls state. */ pthread_mutex_lock(&clone_lock); pthread_mutex_unlock(&clone_lock); + bql_lock(); cpu_loop(env); /* never exits */ return NULL; @@ -13772,6 +13774,8 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + bql_unlock(); + if (unlikely(qemu_loglevel_mask(LOG_STRACE))) { print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6); } @@ -13784,6 +13788,8 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, arg3, arg4, arg5, arg6); } + bql_lock(); + record_syscall_return(cpu, num, ret); return ret; } diff --git a/system/cpus.c b/system/cpus.c index 1c818ff6828..fe84b822798 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -65,9 +65,6 @@ #endif /* CONFIG_LINUX */ -/* The Big QEMU Lock (BQL) */ -static QemuMutex bql; - /* * The chosen accelerator is supposed to register this. */ @@ -420,16 +417,10 @@ void qemu_init_cpu_loop(void) qemu_init_sigbus(); qemu_cond_init(&qemu_cpu_cond); qemu_cond_init(&qemu_pause_cond); - qemu_mutex_init(&bql); qemu_thread_get_self(&io_thread); } -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 void qemu_cpu_stop(CPUState *cpu, bool exit) { g_assert(qemu_cpu_is_self(cpu)); @@ -459,7 +450,7 @@ void qemu_wait_io_event(CPUState *cpu) slept = true; qemu_plugin_vcpu_idle_cb(cpu); } - qemu_cond_wait(cpu->halt_cond, &bql); + qemu_cond_wait_bql(cpu->halt_cond); } if (slept) { qemu_plugin_vcpu_resume_cb(cpu); @@ -512,48 +503,11 @@ bool qemu_in_vcpu_thread(void) return current_cpu && qemu_cpu_is_self(current_cpu); } -QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked) - -bool bql_locked(void) -{ - return get_bql_locked(); -} - bool qemu_in_main_thread(void) { return bql_locked(); } -/* - * The BQL is taken from so many places that it is worth profiling the - * callers directly, instead of funneling them all through a single function. - */ -void bql_lock_impl(const char *file, int line) -{ - QemuMutexLockFunc bql_lock_fn = qatomic_read(&bql_mutex_lock_func); - - g_assert(!bql_locked()); - bql_lock_fn(&bql, file, line); - set_bql_locked(true); -} - -void bql_unlock(void) -{ - g_assert(bql_locked()); - set_bql_locked(false); - qemu_mutex_unlock(&bql); -} - -void qemu_cond_wait_bql(QemuCond *cond) -{ - qemu_cond_wait(cond, &bql); -} - -void qemu_cond_timedwait_bql(QemuCond *cond, int ms) -{ - qemu_cond_timedwait(cond, &bql, ms); -} - /* signal CPU creation */ void cpu_thread_signal_created(CPUState *cpu) { @@ -613,7 +567,7 @@ void pause_all_vcpus(void) replay_mutex_unlock(); while (!all_vcpus_paused()) { - qemu_cond_wait(&qemu_pause_cond, &bql); + qemu_cond_wait_bql(&qemu_pause_cond); CPU_FOREACH(cpu) { qemu_cpu_kick(cpu); } @@ -684,7 +638,7 @@ void qemu_init_vcpu(CPUState *cpu) cpus_accel->create_vcpu_thread(cpu); while (!cpu->created) { - qemu_cond_wait(&qemu_cpu_cond, &bql); + qemu_cond_wait_bql(&qemu_cpu_cond); } } -- 2.46.0