From patchwork Fri Feb 22 18:10:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 15034 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id CB81E23F78 for ; Fri, 22 Feb 2013 18:10:27 +0000 (UTC) Received: from mail-vc0-f177.google.com (mail-vc0-f177.google.com [209.85.220.177]) by fiordland.canonical.com (Postfix) with ESMTP id 71D4FA18B66 for ; Fri, 22 Feb 2013 18:10:27 +0000 (UTC) Received: by mail-vc0-f177.google.com with SMTP id m18so583670vcm.36 for ; Fri, 22 Feb 2013 10:10:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=9TMJ1WJHKWBD3saaD2zCNyNFpdZtkBR27D0c+FzXW9U=; b=NEr3jXx7EHxBh3C0qTb7fDMRgdRUvO+tsHz153uSwZTSx8yrghrNIiFO8YrhjsLdBE iLGAsutIAG4VZ1bLjgShu1obO82OwSoMJgR8D8cyaOSYQeFb2PmDjwGME6ZdShvKQSkV 8t8H5W511QSnRlGb8vRZkQKZDe6ZXyHcvRDEgY3dgYRUl3Stlo4JI7oXDXxUUDsflW8v bocyPvP730foE1dvA4J3jkEuU1aohhLBpE5lMrTy0D1drOqApPlkJFJCmZR/ebTHLH21 MoMiuxeOC61hvk3ln5rmdAbS+hPeJoJgINP+AJmGryE1X1rShDvDzFTJO1698hAp34T5 9Xrg== X-Received: by 10.58.84.164 with SMTP id a4mr4098194vez.9.1361556626898; Fri, 22 Feb 2013 10:10:26 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.145.101 with SMTP id st5csp101298veb; Fri, 22 Feb 2013 10:10:24 -0800 (PST) X-Received: by 10.180.80.35 with SMTP id o3mr336939wix.9.1361556623766; Fri, 22 Feb 2013 10:10:23 -0800 (PST) Received: from mnementh.archaic.org.uk (1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.1.0.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id du1si1187047wib.52.2013.02.22.10.10.23 (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 22 Feb 2013 10:10:23 -0800 (PST) Received-SPF: neutral (google.com: 2001:8b0:1d0::1 is neither permitted nor denied by best guess record for domain of pm215@archaic.org.uk) client-ip=2001:8b0:1d0::1; Authentication-Results: mx.google.com; spf=neutral (google.com: 2001:8b0:1d0::1 is neither permitted nor denied by best guess record for domain of pm215@archaic.org.uk) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1U8x4Q-0005io-2n; Fri, 22 Feb 2013 18:10:06 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Blue Swirl , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Paul Brook , Anthony Liguori , Richard Henderson , Alexander Graf Subject: [PATCH 4/6] Handle CPU interrupts by inline checking of a flag Date: Fri, 22 Feb 2013 18:10:03 +0000 Message-Id: <1361556605-21963-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1361556605-21963-1-git-send-email-peter.maydell@linaro.org> References: <1361556605-21963-1-git-send-email-peter.maydell@linaro.org> X-Gm-Message-State: ALoCoQmbwHK4S5xuMfLG03atBZMtt4DoIVvJjlYO2OcbofemtkwnEEeLd/+UEGFsO3uQrfk96QP8 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 --- cpu-exec.c | 25 ++++++++++++++++++++++++- exec.c | 2 +- include/exec/gen-icount.h | 12 ++++++++++++ include/qom/cpu.h | 3 +++ tcg/tcg.h | 5 +++++ translate-all.c | 4 ++-- 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index e80626a..6f4cc36 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -64,6 +64,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); cpu_pc_from_tb(env, tb); } + if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) { + /* We were asked to stop executing TBs (probably a pending + * interrupt. We've now stopped, so clear the flag. + */ + cpu->tcg_exit_req = 0; + } return next_tb; } @@ -608,7 +614,20 @@ int cpu_exec(CPUArchState *env) tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = cpu_tb_exec(cpu, tc_ptr); - if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { + switch (next_tb & TB_EXIT_MASK) { + case TB_EXIT_REQUESTED: + /* Something asked us to stop executing + * chained TBs; just continue round the main + * loop. Whatever requested the exit will also + * have set something else (eg exit_request or + * interrupt_request) which we will handle + * next time around the loop. + */ + tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); + next_tb = 0; + break; + case TB_EXIT_ICOUNT_EXPIRED: + { /* Instruction counter expired. */ int insns_left; tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); @@ -632,6 +651,10 @@ int cpu_exec(CPUArchState *env) next_tb = 0; cpu_loop_exit(env); } + break; + } + default: + break; } } cpu->current_tb = NULL; diff --git a/exec.c b/exec.c index a41bcb8..46a2830 100644 --- a/exec.c +++ b/exec.c @@ -495,7 +495,7 @@ void cpu_exit(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); cpu->exit_request = 1; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } void cpu_abort(CPUArchState *env, const char *fmt, ...) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index c858a73..384153b 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -7,10 +7,19 @@ 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; @@ -29,6 +38,9 @@ static inline void gen_icount_start(void) 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); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ee1a7c8..ab2657c 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -71,6 +71,8 @@ struct kvm_run; * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @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. * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @kvm_fd: vCPU file descriptor for KVM. @@ -100,6 +102,7 @@ struct CPUState { bool stop; bool stopped; volatile sig_atomic_t exit_request; + volatile sig_atomic_t tcg_exit_req; void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; diff --git a/tcg/tcg.h b/tcg/tcg.h index 2ebde07..90375c0 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -695,6 +695,10 @@ TCGv_i64 tcg_const_local_i64(int64_t val); * would hit zero midway through it. In this case the next-TB pointer * returned is the TB we were about to execute, and the caller must * arrange to execute the remaining count of instructions. + * 3: we stopped because the CPU's exit_request flag was set + * (usually meaning that there is an interrupt that needs to be + * handled). The next-TB pointer returned is the TB we were + * about to execute when we noticed the pending exit request. * * If the bottom two bits indicate an exit-via-index then the CPU * state is correctly synchronised and ready for execution of the next @@ -711,6 +715,7 @@ TCGv_i64 tcg_const_local_i64(int64_t val); #define TB_EXIT_IDX0 0 #define TB_EXIT_IDX1 1 #define TB_EXIT_ICOUNT_EXPIRED 2 +#define TB_EXIT_REQUESTED 3 #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ diff --git a/translate-all.c b/translate-all.c index b50fb89..9741d96 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1475,7 +1475,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask) cpu_abort(env, "Raised interrupt while not in I/O function"); } } else { - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } } @@ -1626,7 +1626,7 @@ void cpu_interrupt(CPUArchState *env, int mask) CPUState *cpu = ENV_GET_CPU(env); env->interrupt_request |= mask; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } /*