aboutsummaryrefslogtreecommitdiffstats
path: root/cpu-exec.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2010-06-25 16:56:50 +0200
committerAurelien Jarno <aurelien@aurel32.net>2010-07-22 05:52:09 +0200
commitb0052d15315f672d30da5f0ea0a57b1a7c232a03 (patch)
treea4a1255381ac5f359c917f405312c28657ee1424 /cpu-exec.c
parent1d93f0f03d4d911fdf1dc4ef529d8b2a0c0765f2 (diff)
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>
Diffstat (limited to 'cpu-exec.c')
-rw-r--r--cpu-exec.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/cpu-exec.c b/cpu-exec.c
index 525b3b45e..5f88f3fa8 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -600,8 +600,9 @@ int cpu_exec(CPUState *env1)
TB, but before it is linked into a potentially
infinite loop and becomes env->current_tb. Avoid
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;
/* execute the generated code */
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
@@ -610,7 +611,6 @@ int cpu_exec(CPUState *env1)
#define env cpu_single_env
#endif
next_tb = tcg_qemu_tb_exec(tc_ptr);
- env->current_tb = NULL;
if ((next_tb & 3) == 2) {
/* Instruction counter expired. */
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
only be set by a memory fault) */
} /* for(;;) */