Fix cpu_unlink_tb race
If a signal hit after the env->exit_request check but before cpu_exec updated env->current_tb, cpu_unlink_tb called from the signal hander will not unlink the current TB. This may leave us stuck in a guest loop if no further unlink is invoked. Fix this by reordering current_tb update and exit_request check, additionally enforcing the correct order via a compiler barrier. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
1d93f0f03d
commit
b0052d1531
|
@ -600,8 +600,9 @@ int cpu_exec(CPUState *env1)
|
||||||
TB, but before it is linked into a potentially
|
TB, but before it is linked into a potentially
|
||||||
infinite loop and becomes env->current_tb. Avoid
|
infinite loop and becomes env->current_tb. Avoid
|
||||||
starting execution if there is a pending interrupt. */
|
starting execution if there is a pending interrupt. */
|
||||||
if (!unlikely (env->exit_request)) {
|
env->current_tb = tb;
|
||||||
env->current_tb = tb;
|
barrier();
|
||||||
|
if (likely(!env->exit_request)) {
|
||||||
tc_ptr = tb->tc_ptr;
|
tc_ptr = tb->tc_ptr;
|
||||||
/* execute the generated code */
|
/* execute the generated code */
|
||||||
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
|
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
|
||||||
|
@ -610,7 +611,6 @@ int cpu_exec(CPUState *env1)
|
||||||
#define env cpu_single_env
|
#define env cpu_single_env
|
||||||
#endif
|
#endif
|
||||||
next_tb = tcg_qemu_tb_exec(tc_ptr);
|
next_tb = tcg_qemu_tb_exec(tc_ptr);
|
||||||
env->current_tb = NULL;
|
|
||||||
if ((next_tb & 3) == 2) {
|
if ((next_tb & 3) == 2) {
|
||||||
/* Instruction counter expired. */
|
/* Instruction counter expired. */
|
||||||
int insns_left;
|
int insns_left;
|
||||||
|
@ -639,6 +639,7 @@ int cpu_exec(CPUState *env1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
env->current_tb = NULL;
|
||||||
/* reset soft MMU for next block (it can currently
|
/* reset soft MMU for next block (it can currently
|
||||||
only be set by a memory fault) */
|
only be set by a memory fault) */
|
||||||
} /* for(;;) */
|
} /* for(;;) */
|
||||||
|
|
Loading…
Reference in New Issue