aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-01-07 10:12:51 -0800
committerRichard Henderson <richard.henderson@linaro.org>2023-01-16 10:14:12 -1000
commit61710a7e23a63546da0071ea32adb96476fa5d07 (patch)
tree293b0ada5765b7d0076fc05f8d80254e7673cc08
parent701ea5870d3752173d0c78d79d9d1f57757a8036 (diff)
downloadqemu-61710a7e23a63546da0071ea32adb96476fa5d07.zip
qemu-61710a7e23a63546da0071ea32adb96476fa5d07.tar.gz
qemu-61710a7e23a63546da0071ea32adb96476fa5d07.tar.bz2
accel/tcg: Split out cpu_exec_{setjmp,loop}
Recently the g_assert(cpu == current_cpu) test has been intermittently failing with gcc. Reorg the code around the setjmp to minimize the lifetime of the cpu variable affected by the setjmp. This appears to fix the existing issue with clang as well. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1147 Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--accel/tcg/cpu-exec.c111
1 files changed, 54 insertions, 57 deletions
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 356fe34..8927092 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -909,64 +909,10 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
/* main execution loop */
-int cpu_exec(CPUState *cpu)
+static int __attribute__((noinline))
+cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
{
int ret;
- SyncClocks sc = { 0 };
-
- /* replay_interrupt may need current_cpu */
- current_cpu = cpu;
-
- if (cpu_handle_halt(cpu)) {
- return EXCP_HALTED;
- }
-
- rcu_read_lock();
-
- cpu_exec_enter(cpu);
-
- /* Calculate difference between guest clock and host clock.
- * This delay includes the delay of the last cycle, so
- * what we have to do is sleep until it is 0. As for the
- * advance/delay we gain here, we try to fix it next time.
- */
- init_delay_params(&sc, cpu);
-
- /* prepare setjmp context for exception handling */
- if (sigsetjmp(cpu->jmp_env, 0) != 0) {
-#if defined(__clang__)
- /*
- * Some compilers wrongly smash all local variables after
- * siglongjmp (the spec requires that only non-volatile locals
- * which are changed between the sigsetjmp and siglongjmp are
- * permitted to be trashed). There were bug reports for gcc
- * 4.5.0 and clang. The bug is fixed in all versions of gcc
- * that we support, but is still unfixed in clang:
- * https://bugs.llvm.org/show_bug.cgi?id=21183
- *
- * Reload an essential local variable here for those compilers.
- * Newer versions of gcc would complain about this code (-Wclobbered),
- * so we only perform the workaround for clang.
- */
- cpu = current_cpu;
-#else
- /* Non-buggy compilers preserve this; assert the correct value. */
- g_assert(cpu == current_cpu);
-#endif
-
-#ifndef CONFIG_SOFTMMU
- clear_helper_retaddr();
- if (have_mmap_lock()) {
- mmap_unlock();
- }
-#endif
- if (qemu_mutex_iothread_locked()) {
- qemu_mutex_unlock_iothread();
- }
- qemu_plugin_disable_mem_helpers(cpu);
-
- assert_no_pages_locked();
- }
/* if an exception is pending, we execute it here */
while (!cpu_handle_exception(cpu, &ret)) {
@@ -1033,9 +979,60 @@ int cpu_exec(CPUState *cpu)
/* Try to align the host and virtual clocks
if the guest is in advance */
- align_clocks(&sc, cpu);
+ align_clocks(sc, cpu);
}
}
+ return ret;
+}
+
+static int cpu_exec_setjmp(CPUState *cpu, SyncClocks *sc)
+{
+ /* Prepare setjmp context for exception handling. */
+ if (unlikely(sigsetjmp(cpu->jmp_env, 0) != 0)) {
+ /* Non-buggy compilers preserve this; assert the correct value. */
+ g_assert(cpu == current_cpu);
+
+#ifndef CONFIG_SOFTMMU
+ clear_helper_retaddr();
+ if (have_mmap_lock()) {
+ mmap_unlock();
+ }
+#endif
+ if (qemu_mutex_iothread_locked()) {
+ qemu_mutex_unlock_iothread();
+ }
+ qemu_plugin_disable_mem_helpers(cpu);
+
+ assert_no_pages_locked();
+ }
+
+ return cpu_exec_loop(cpu, sc);
+}
+
+int cpu_exec(CPUState *cpu)
+{
+ int ret;
+ SyncClocks sc = { 0 };
+
+ /* replay_interrupt may need current_cpu */
+ current_cpu = cpu;
+
+ if (cpu_handle_halt(cpu)) {
+ return EXCP_HALTED;
+ }
+
+ rcu_read_lock();
+ cpu_exec_enter(cpu);
+
+ /*
+ * Calculate difference between guest clock and host clock.
+ * This delay includes the delay of the last cycle, so
+ * what we have to do is sleep until it is 0. As for the
+ * advance/delay we gain here, we try to fix it next time.
+ */
+ init_delay_params(&sc, cpu);
+
+ ret = cpu_exec_setjmp(cpu, &sc);
cpu_exec_exit(cpu);
rcu_read_unlock();