378df4b237
Fix some of the nasty TCG race conditions and crashes by implementing cpu_exit() as setting a flag which is checked at the start of each TB. This avoids crashes if a thread or signal handler calls cpu_exit() while the execution thread is itself modifying the TB graph (which may happen in system emulation mode as well as in linux-user mode with a multithreaded guest binary). This fixes the crashes seen in LP:668799; however there are another class of crashes described in LP:1098729 which stem from the fact that in linux-user with a multithreaded guest all threads will use and modify the same global TCG date structures (including the generated code buffer) without any kind of locking. This means that multithreaded guest binaries are still in the "unsupported" category. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
66 lines
1.7 KiB
C
66 lines
1.7 KiB
C
#ifndef GEN_ICOUNT_H
|
|
#define GEN_ICOUNT_H 1
|
|
|
|
#include "qemu/timer.h"
|
|
|
|
/* Helpers for instruction counting code generation. */
|
|
|
|
static TCGArg *icount_arg;
|
|
static int icount_label;
|
|
static int exitreq_label;
|
|
|
|
static inline void gen_icount_start(void)
|
|
{
|
|
TCGv_i32 count;
|
|
TCGv_i32 flag;
|
|
|
|
exitreq_label = gen_new_label();
|
|
flag = tcg_temp_local_new_i32();
|
|
tcg_gen_ld_i32(flag, cpu_env,
|
|
offsetof(CPUState, tcg_exit_req) - ENV_OFFSET);
|
|
tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label);
|
|
tcg_temp_free_i32(flag);
|
|
|
|
if (!use_icount)
|
|
return;
|
|
|
|
icount_label = gen_new_label();
|
|
count = tcg_temp_local_new_i32();
|
|
tcg_gen_ld_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u32));
|
|
/* This is a horrid hack to allow fixing up the value later. */
|
|
icount_arg = tcg_ctx.gen_opparam_ptr + 1;
|
|
tcg_gen_subi_i32(count, count, 0xdeadbeef);
|
|
|
|
tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
|
|
tcg_gen_st16_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u16.low));
|
|
tcg_temp_free_i32(count);
|
|
}
|
|
|
|
static void gen_icount_end(TranslationBlock *tb, int num_insns)
|
|
{
|
|
gen_set_label(exitreq_label);
|
|
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED);
|
|
|
|
if (use_icount) {
|
|
*icount_arg = num_insns;
|
|
gen_set_label(icount_label);
|
|
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_ICOUNT_EXPIRED);
|
|
}
|
|
}
|
|
|
|
static inline void gen_io_start(void)
|
|
{
|
|
TCGv_i32 tmp = tcg_const_i32(1);
|
|
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUArchState, can_do_io));
|
|
tcg_temp_free_i32(tmp);
|
|
}
|
|
|
|
static inline void gen_io_end(void)
|
|
{
|
|
TCGv_i32 tmp = tcg_const_i32(0);
|
|
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUArchState, can_do_io));
|
|
tcg_temp_free_i32(tmp);
|
|
}
|
|
|
|
#endif
|