]> git.proxmox.com Git - qemu.git/commitdiff
Fix cpu_unlink_tb race
authorJan Kiszka <jan.kiszka@siemens.com>
Fri, 25 Jun 2010 14:56:50 +0000 (16:56 +0200)
committerAurelien Jarno <aurelien@aurel32.net>
Thu, 22 Jul 2010 03:52:09 +0000 (05:52 +0200)
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>
cpu-exec.c

index 525b3b45ee6fbe3e9d4d8056441999924b2393da..5f88f3fa893716e8ccfe9068b937e6a478eae42b 100644 (file)
@@ -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(;;) */