From: KONRAD Frederic <fred.kon...@greensocs.com> This flag indicates the state of the VCPU thread: * 0 if the VCPU is allowed to execute code. * 1 if the VCPU is currently executing code. * -1 if the VCPU is not allowed to execute code.
This allows to atomically check and run safe work or check and continue the TCG execution. Signed-off-by: KONRAD Frederic <fred.kon...@greensocs.com> Changes V2 -> V3: * introduce a third state which allow or not the execution. * atomically check and set the flag when starting or blocking the code execution. Changes V1 -> V2: * do both tcg_executing = 0 or 1 in cpu_exec(). --- cpu-exec.c | 5 +++++ include/qom/cpu.h | 32 ++++++++++++++++++++++++++++++++ qom/cpu.c | 19 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index 75694f3..e16666a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -371,6 +371,10 @@ int cpu_exec(CPUState *cpu) cpu->halted = 0; } + if (!tcg_cpu_try_start_execution(cpu)) { + cpu->exit_request = 1; + return 0; + } current_cpu = cpu; /* As long as current_cpu is null, up to the assignment just above, @@ -583,5 +587,6 @@ int cpu_exec(CPUState *cpu) /* fail safe : never use current_cpu outside cpu_exec() */ current_cpu = NULL; + tcg_cpu_allow_execution(cpu); return ret; } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index efa9624..de7487e 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -226,6 +226,7 @@ struct kvm_run; * @stopped: Indicates the CPU has been artificially stopped. * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this * CPU and return to its top level loop. + * @tcg_exec_flag: See tcg_cpu_flag_* function. * @singlestep_enabled: Flags for single-stepping. * @icount_extra: Instructions until next timer event. * @icount_decr: Number of cycles left, with interrupt flag in high bit. @@ -322,6 +323,8 @@ struct CPUState { (absolute value) offset as small as possible. This reduces code size, especially for hosts without large memory offsets. */ volatile sig_atomic_t tcg_exit_req; + + int tcg_exec_flag; }; QTAILQ_HEAD(CPUTailQ, CPUState); @@ -337,6 +340,35 @@ extern struct CPUTailQ cpus; DECLARE_TLS(CPUState *, current_cpu); #define current_cpu tls_var(current_cpu) + +/** + * tcg_cpu_try_block_execution + * @cpu: The CPU to block the execution + * + * Try to set the tcg_exec_flag to -1 saying the CPU can't execute code if the + * CPU is not executing code. + * Returns true if the cpu execution is blocked, false otherwise. + */ +bool tcg_cpu_try_block_execution(CPUState *cpu); + +/** + * tcg_cpu_allow_execution + * @cpu: The CPU to allow the execution. + * + * Just reset the state of tcg_exec_flag, and allow the execution of some code. + */ +void tcg_cpu_allow_execution(CPUState *cpu); + +/** + * tcg_cpu_try_start_execution + * @cpu: The CPU to start the execution. + * + * Just set the tcg_exec_flag to 1 saying the CPU is executing code if the CPU + * is allowed to run some code. + * Returns true if the cpu can execute, false otherwise. + */ +bool tcg_cpu_try_start_execution(CPUState *cpu); + /** * cpu_paging_enabled: * @cpu: The CPU whose state is to be inspected. diff --git a/qom/cpu.c b/qom/cpu.c index 4e12598..e32f90c 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -26,6 +26,23 @@ #include "qemu/error-report.h" #include "sysemu/sysemu.h" +bool tcg_cpu_try_block_execution(CPUState *cpu) +{ + return (atomic_cmpxchg(&cpu->tcg_exec_flag, 0, -1) + || (cpu->tcg_exec_flag == -1)); +} + +void tcg_cpu_allow_execution(CPUState *cpu) +{ + cpu->tcg_exec_flag = 0; +} + +bool tcg_cpu_try_start_execution(CPUState *cpu) +{ + return (atomic_cmpxchg(&cpu->tcg_exec_flag, 0, 1) + || (cpu->tcg_exec_flag == 1)); +} + bool cpu_exists(int64_t id) { CPUState *cpu; @@ -249,6 +266,8 @@ static void cpu_common_reset(CPUState *cpu) cpu->icount_decr.u32 = 0; cpu->can_do_io = 0; cpu->exception_index = -1; + + tcg_cpu_allow_execution(cpu); memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); } -- 1.9.0