diff mbox series

[RFC,v3,48/56] ppc: acquire the BQL in cpu_has_work

Message ID 20181019010625.25294-49-cota@braap.org
State New
Headers show
Series per-CPU locks | expand

Commit Message

Emilio Cota Oct. 19, 2018, 1:06 a.m. UTC
Soon we will call cpu_has_work without the BQL.

Cc: David Gibson <david@gibson.dropbear.id.au>
Cc: Alexander Graf <agraf@suse.de>
Cc: qemu-ppc@nongnu.org
Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 target/ppc/translate_init.inc.c | 77 +++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 4 deletions(-)

Comments

Paolo Bonzini Oct. 19, 2018, 6:58 a.m. UTC | #1
On 19/10/2018 03:06, Emilio G. Cota wrote:
> Soon we will call cpu_has_work without the BQL.
> 
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Cc: Alexander Graf <agraf@suse.de>
> Cc: qemu-ppc@nongnu.org
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> ---
>  target/ppc/translate_init.inc.c | 77 +++++++++++++++++++++++++++++++--
>  1 file changed, 73 insertions(+), 4 deletions(-)
> 

Perhaps we should instead define both ->cpu_has_work and
->cpu_has_work_with_iothread_lock members, and move the generic
unlock/relock code to common code?

Paolo
Emilio Cota Oct. 20, 2018, 4:31 p.m. UTC | #2
On Fri, Oct 19, 2018 at 08:58:31 +0200, Paolo Bonzini wrote:
> On 19/10/2018 03:06, Emilio G. Cota wrote:
> > Soon we will call cpu_has_work without the BQL.
> > 
> > Cc: David Gibson <david@gibson.dropbear.id.au>
> > Cc: Alexander Graf <agraf@suse.de>
> > Cc: qemu-ppc@nongnu.org
> > Signed-off-by: Emilio G. Cota <cota@braap.org>
> > ---
> >  target/ppc/translate_init.inc.c | 77 +++++++++++++++++++++++++++++++--
> >  1 file changed, 73 insertions(+), 4 deletions(-)
> > 
> 
> Perhaps we should instead define both ->cpu_has_work and
> ->cpu_has_work_with_iothread_lock members, and move the generic
> unlock/relock code to common code?

I like this. How does the appended look?

Thanks,

		Emilio
---8<---

[PATCH] cpu: introduce cpu_has_work_with_iothread_lock

It will gain some users soon.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 include/qom/cpu.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index ad8859d014..d9e6f5d4d2 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -26,6 +26,7 @@
 #include "exec/memattrs.h"
 #include "qapi/qapi-types-run-state.h"
 #include "qemu/bitmap.h"
+#include "qemu/main-loop.h"
 #include "qemu/rcu_queue.h"
 #include "qemu/queue.h"
 #include "qemu/thread.h"
@@ -86,6 +87,8 @@ struct TranslationBlock;
  * @reset_dump_flags: #CPUDumpFlags to use for reset logging.
  * @has_work: Callback for checking if there is work to do. Called with the
  * CPU lock held.
+ * @has_work_with_iothread_lock: Callback for checking if there is work to do.
+ * Called with both the BQL and the CPU lock held.
  * @do_interrupt: Callback for interrupt handling.
  * @do_unassigned_access: Callback for unassigned access handling.
  * (this is deprecated: new targets should use do_transaction_failed instead)
@@ -157,6 +160,7 @@ typedef struct CPUClass {
     void (*reset)(CPUState *cpu);
     int reset_dump_flags;
     bool (*has_work)(CPUState *cpu);
+    bool (*has_work_with_iothread_lock)(CPUState *cpu);
     void (*do_interrupt)(CPUState *cpu);
     CPUUnassignedAccess do_unassigned_access;
     void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
@@ -774,6 +778,40 @@ CPUState *cpu_create(const char *typename);
  */
 const char *parse_cpu_model(const char *cpu_model);
 
+/* do not call directly; use cpu_has_work instead */
+static inline bool cpu_has_work_bql(CPUState *cpu)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    bool has_cpu_lock = cpu_mutex_locked(cpu);
+    bool has_bql = qemu_mutex_iothread_locked();
+    bool ret;
+
+    if (has_bql) {
+        if (has_cpu_lock) {
+            return cc->has_work_with_iothread_lock(cpu);
+        }
+        cpu_mutex_lock(cpu);
+        ret = cc->has_work_with_iothread_lock(cpu);
+        cpu_mutex_unlock(cpu);
+        return ret;
+    }
+
+    if (has_cpu_lock) {
+        /* avoid deadlock by acquiring the locks in order */
+        cpu_mutex_unlock(cpu);
+    }
+    qemu_mutex_lock_iothread();
+    cpu_mutex_lock(cpu);
+
+    ret = cc->has_work_with_iothread_lock(cpu);
+
+    qemu_mutex_unlock_iothread();
+    if (!has_cpu_lock) {
+        cpu_mutex_unlock(cpu);
+    }
+    return ret;
+}
+
 /**
  * cpu_has_work:
  * @cpu: The vCPU to check.
@@ -787,6 +825,10 @@ static inline bool cpu_has_work(CPUState *cpu)
     CPUClass *cc = CPU_GET_CLASS(cpu);
     bool ret;
 
+    if (cc->has_work_with_iothread_lock) {
+        return cpu_has_work_bql(cpu);
+    }
+
     g_assert(cc->has_work);
     if (cpu_mutex_locked(cpu)) {
         return cc->has_work(cpu);
Richard Henderson Oct. 21, 2018, 1:42 p.m. UTC | #3
On 10/20/18 5:31 PM, Emilio G. Cota wrote:
> I like this. How does the appended look?
> 
> Thanks,
> 
> 		Emilio
> ---8<---
> 
> [PATCH] cpu: introduce cpu_has_work_with_iothread_lock

I might just inline cpu_has_work_bql into the one caller.
You could even share has_cpu_lock with the code there.


r~
diff mbox series

Patch

diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 6827db14b6..a206715873 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -18,6 +18,7 @@ 
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "qemu/main-loop.h"
 #include "disas/bfd.h"
 #include "exec/gdbstub.h"
 #include "kvm_ppc.h"
@@ -8440,11 +8441,13 @@  static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
     return false;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
+static bool cpu_has_work_POWER7_locked(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
+    g_assert(qemu_mutex_iothread_locked());
+
     if (cpu_halted(cs)) {
         if (!(cpu_interrupt_request(cs) & CPU_INTERRUPT_HARD)) {
             return false;
@@ -8474,6 +8477,21 @@  static bool cpu_has_work_POWER7(CPUState *cs)
     }
 }
 
+static bool cpu_has_work_POWER7(CPUState *cs)
+{
+    if (!qemu_mutex_iothread_locked()) {
+        bool ret;
+
+        cpu_mutex_unlock(cs);
+        qemu_mutex_lock_iothread();
+        cpu_mutex_lock(cs);
+        ret = cpu_has_work_POWER7_locked(cs);
+        qemu_mutex_unlock_iothread();
+        return ret;
+    }
+    return cpu_has_work_POWER7_locked(cs);
+}
+
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -8594,11 +8612,13 @@  static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
     return false;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
+static bool cpu_has_work_POWER8_locked(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
+    g_assert(qemu_mutex_iothread_locked());
+
     if (cpu_halted(cs)) {
         if (!(cpu_interrupt_request(cs) & CPU_INTERRUPT_HARD)) {
             return false;
@@ -8636,6 +8656,21 @@  static bool cpu_has_work_POWER8(CPUState *cs)
     }
 }
 
+static bool cpu_has_work_POWER8(CPUState *cs)
+{
+    if (!qemu_mutex_iothread_locked()) {
+        bool ret;
+
+        cpu_mutex_unlock(cs);
+        qemu_mutex_lock_iothread();
+        cpu_mutex_lock(cs);
+        ret = cpu_has_work_POWER8_locked(cs);
+        qemu_mutex_unlock_iothread();
+        return ret;
+    }
+    return cpu_has_work_POWER8_locked(cs);
+}
+
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -8786,11 +8821,13 @@  static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
     return false;
 }
 
-static bool cpu_has_work_POWER9(CPUState *cs)
+static bool cpu_has_work_POWER9_locked(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
+    g_assert(qemu_mutex_iothread_locked());
+
     if (cpu_halted(cs)) {
         if (!(cpu_interrupt_request(cs) & CPU_INTERRUPT_HARD)) {
             return false;
@@ -8829,6 +8866,21 @@  static bool cpu_has_work_POWER9(CPUState *cs)
     }
 }
 
+static bool cpu_has_work_POWER9(CPUState *cs)
+{
+    if (!qemu_mutex_iothread_locked()) {
+        bool ret;
+
+        cpu_mutex_unlock(cs);
+        qemu_mutex_lock_iothread();
+        cpu_mutex_lock(cs);
+        ret = cpu_has_work_POWER9_locked(cs);
+        qemu_mutex_unlock_iothread();
+        return ret;
+    }
+    return cpu_has_work_POWER9_locked(cs);
+}
+
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -10231,14 +10283,31 @@  static void ppc_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.nip = value;
 }
 
-static bool ppc_cpu_has_work(CPUState *cs)
+static bool ppc_cpu_has_work_locked(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
+    g_assert(qemu_mutex_iothread_locked());
+
     return msr_ee && (cpu_interrupt_request(cs) & CPU_INTERRUPT_HARD);
 }
 
+static bool ppc_cpu_has_work(CPUState *cs)
+{
+    if (!qemu_mutex_iothread_locked()) {
+        bool ret;
+
+        cpu_mutex_unlock(cs);
+        qemu_mutex_lock_iothread();
+        cpu_mutex_lock(cs);
+        ret = ppc_cpu_has_work_locked(cs);
+        qemu_mutex_unlock_iothread();
+        return ret;
+    }
+    return ppc_cpu_has_work_locked(cs);
+}
+
 /* CPUClass::reset() */
 static void ppc_cpu_reset(CPUState *s)
 {