diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2010-06-25 16:56:50 +0200 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2010-07-22 05:52:09 +0200 |
commit | b0052d15315f672d30da5f0ea0a57b1a7c232a03 (patch) | |
tree | a4a1255381ac5f359c917f405312c28657ee1424 | |
parent | 1d93f0f03d4d911fdf1dc4ef529d8b2a0c0765f2 (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>
-rw-r--r-- | cpu-exec.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index 525b3b45ee..5f88f3fa89 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(;;) */ |