Patchwork [2/8] Fix cpu_unlink_tb race

login
register
mail settings
Submitter Jan Kiszka
Date June 25, 2010, 2:56 p.m.
Message ID <7ceaffcd130810af3a45be25bf39de96831e47ed.1277477810.git.jan.kiszka@siemens.com>
Download mbox | patch
Permalink /patch/56987/
State New
Headers show

Comments

Jan Kiszka - June 25, 2010, 2:56 p.m.
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>
---
 cpu-exec.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

Patch

diff --git a/cpu-exec.c b/cpu-exec.c
index 525b3b4..5f88f3f 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(;;) */