diff mbox series

[v4,09/13] accel/all: Extract common_vcpu_thread_create()

Message ID 20220323171751.78612-10-philippe.mathieu.daude@gmail.com (mailing list archive)
State New, archived
Headers show
Series accel: Fix vCPU memory leaks | expand

Commit Message

Philippe Mathieu-Daudé March 23, 2022, 5:17 p.m. UTC
From: Philippe Mathieu-Daudé <f4bug@amsat.org>

All accelerators implement a very similar create_vcpu_thread()
handler. Extract the common part as common_vcpu_thread_create(),
which only requires the AccelOpsClass::vcpu_thread_fn() routine
and the accelerator AccelOpsClass::thread_name for debugging
purpose.

The single exception is TCG/RR which re-use a single vCPU. Have
it use the same logic by using the .precheck/.postcheck handlers.

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 accel/accel-softmmu.c             |  2 +-
 accel/dummy-cpus.c                | 15 +--------------
 accel/hvf/hvf-accel-ops.c         | 18 +++---------------
 accel/kvm/kvm-accel-ops.c         | 17 +++--------------
 accel/qtest/qtest.c               |  3 ++-
 accel/tcg/tcg-accel-ops-mttcg.c   | 22 +---------------------
 accel/tcg/tcg-accel-ops-mttcg.h   |  3 +--
 accel/tcg/tcg-accel-ops-rr.c      | 21 +++------------------
 accel/tcg/tcg-accel-ops-rr.h      |  6 ++++--
 accel/tcg/tcg-accel-ops.c         |  6 ++++--
 accel/xen/xen-all.c               |  2 +-
 include/sysemu/accel-ops.h        |  3 ++-
 include/sysemu/cpus.h             |  4 ++--
 softmmu/cpus.c                    | 23 ++++++++++++++++++++---
 target/i386/hax/hax-accel-ops.c   | 20 ++------------------
 target/i386/nvmm/nvmm-accel-ops.c | 17 +++--------------
 target/i386/whpx/whpx-accel-ops.c | 20 +++-----------------
 17 files changed, 56 insertions(+), 146 deletions(-)

Comments

Richard Henderson March 23, 2022, 10:11 p.m. UTC | #1
On 3/23/22 10:17, Philippe Mathieu-Daudé wrote:
> From: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
> All accelerators implement a very similar create_vcpu_thread()
> handler. Extract the common part as common_vcpu_thread_create(),
> which only requires the AccelOpsClass::vcpu_thread_fn() routine
> and the accelerator AccelOpsClass::thread_name for debugging
> purpose.
> 
> The single exception is TCG/RR which re-use a single vCPU. Have
> it use the same logic by using the .precheck/.postcheck handlers.
> 
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Too much all at once.
But I see now why you moved code in the direction you did in patch 5.

> @@ -279,28 +279,13 @@ bool rr_create_vcpu_thread_precheck(CPUState *cpu)
>       return !single_tcg_cpu_thread;
>   }
>   
> -void rr_start_vcpu_thread(CPUState *cpu)
> +void rr_create_vcpu_thread_postcheck(CPUState *cpu)
>   {
> -    char thread_name[VCPU_THREAD_NAME_SIZE];
>       static QemuCond *single_tcg_halt_cond;
> -    static QemuThread *single_tcg_cpu_thread;

Patch 8 is not really standalone, since you didn't move this variable.
I think it's probably a mistake to split out precheck and postcheck separately.

> -
> -    if (!single_tcg_cpu_thread) {
> +    if (! single_tcg_cpu_thread) {

Extraneous whitespace.

> @@ -30,7 +30,8 @@ struct AccelOpsClass {
>   
>       bool (*cpus_are_resettable)(void);
>   
> -    void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY NON-NULL */
> +    const char *thread_name;

Why don't we just get this name from the AccelClass?

> +static void common_vcpu_thread_create(CPUState *cpu)
> +{
> +    char thread_name[VCPU_THREAD_NAME_SIZE];
> +
> +    cpu->thread = g_new0(QemuThread, 1);
> +    cpu->halt_cond = g_new0(QemuCond, 1);
> +    qemu_cond_init(cpu->halt_cond);
> +    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/%s",
> +             cpu->cpu_index, cpus_accel->thread_name ?: "DUMMY");

Surely g_strdup_printf is better than the static size buffer.


r~
Richard Henderson March 23, 2022, 10:15 p.m. UTC | #2
On 3/23/22 10:17, Philippe Mathieu-Daudé wrote:
> +void rr_create_vcpu_thread_postcheck(CPUState *cpu)
>   {
> -    char thread_name[VCPU_THREAD_NAME_SIZE];
>       static QemuCond *single_tcg_halt_cond;
> -    static QemuThread *single_tcg_cpu_thread;
> -
> -    if (!single_tcg_cpu_thread) {
> -        cpu->thread = g_new0(QemuThread, 1);
> -        cpu->halt_cond = g_new0(QemuCond, 1);
> -        qemu_cond_init(cpu->halt_cond);
> -
> -        /* share a single thread for all cpus with TCG */
> -        snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "ALL CPUs/TCG");
> -        qemu_thread_create(cpu->thread, thread_name,
> -                           rr_cpu_thread_fn,
> -                           cpu, QEMU_THREAD_JOINABLE);
>   
> +    if (! single_tcg_cpu_thread) {
>           single_tcg_halt_cond = cpu->halt_cond;
>           single_tcg_cpu_thread = cpu->thread;
> -#ifdef _WIN32
> -        cpu->hThread = qemu_thread_get_handle(cpu->thread);
> -#endif
>       } else {
>           /* we share the thread */
>           cpu->thread = single_tcg_cpu_thread;

This doesn't treat cpu->halt_cond correctly for other than the first cpu.


r~
diff mbox series

Patch

diff --git a/accel/accel-softmmu.c b/accel/accel-softmmu.c
index 67276e4f52..7800df0234 100644
--- a/accel/accel-softmmu.c
+++ b/accel/accel-softmmu.c
@@ -77,7 +77,7 @@  void accel_init_ops_interfaces(AccelClass *ac)
 
     /*
      * all accelerators need to define ops, providing at least a mandatory
-     * non-NULL create_vcpu_thread operation.
+     * non-NULL vcpu_thread_fn operation.
      */
     g_assert(ops != NULL);
     if (ops->ops_init) {
diff --git a/accel/dummy-cpus.c b/accel/dummy-cpus.c
index 10429fdfb2..9840057969 100644
--- a/accel/dummy-cpus.c
+++ b/accel/dummy-cpus.c
@@ -18,7 +18,7 @@ 
 #include "qemu/main-loop.h"
 #include "hw/core/cpu.h"
 
-static void *dummy_cpu_thread_fn(void *arg)
+void *dummy_vcpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
     sigset_t waitset;
@@ -57,16 +57,3 @@  static void *dummy_cpu_thread_fn(void *arg)
     rcu_unregister_thread();
     return NULL;
 }
-
-void dummy_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_malloc0(sizeof(QemuThread));
-    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
-    qemu_cond_init(cpu->halt_cond);
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/DUMMY",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, dummy_cpu_thread_fn, cpu,
-                       QEMU_THREAD_JOINABLE);
-}
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
index 5c33dc602e..91d65036b4 100644
--- a/accel/hvf/hvf-accel-ops.c
+++ b/accel/hvf/hvf-accel-ops.c
@@ -442,25 +442,13 @@  static void *hvf_cpu_thread_fn(void *arg)
     return NULL;
 }
 
-static void hvf_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_malloc0(sizeof(QemuThread));
-    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
-    qemu_cond_init(cpu->halt_cond);
-
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, hvf_cpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-}
-
 static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = hvf_start_vcpu_thread;
+    ops->thread_name = "HVF";
+    ops->vcpu_thread_fn = hvf_cpu_thread_fn;
+
     ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
 
     ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index c4244a23c6..3d13efce0f 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -61,19 +61,6 @@  static void *kvm_vcpu_thread_fn(void *arg)
     return NULL;
 }
 
-static void kvm_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_malloc0(sizeof(QemuThread));
-    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
-    qemu_cond_init(cpu->halt_cond);
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, kvm_vcpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-}
-
 static bool kvm_vcpu_thread_is_idle(CPUState *cpu)
 {
     return !kvm_halt_in_kernel();
@@ -88,7 +75,9 @@  static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = kvm_start_vcpu_thread;
+    ops->thread_name = "KVM";
+    ops->vcpu_thread_fn = kvm_vcpu_thread_fn;
+
     ops->cpu_thread_is_idle = kvm_vcpu_thread_is_idle;
     ops->cpus_are_resettable = kvm_cpus_are_resettable;
     ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset;
diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c
index f6056ac836..1d0b1c855c 100644
--- a/accel/qtest/qtest.c
+++ b/accel/qtest/qtest.c
@@ -50,7 +50,8 @@  static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = dummy_start_vcpu_thread;
+    ops->vcpu_thread_fn = dummy_vcpu_thread_fn;
+
     ops->get_virtual_clock = qtest_get_virtual_clock;
 };
 
diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c
index 80609964a6..c7836332d7 100644
--- a/accel/tcg/tcg-accel-ops-mttcg.c
+++ b/accel/tcg/tcg-accel-ops-mttcg.c
@@ -63,7 +63,7 @@  static void mttcg_force_rcu(Notifier *notify, void *data)
  * current CPUState for a given thread.
  */
 
-static void *mttcg_cpu_thread_fn(void *arg)
+void *mttcg_vcpu_thread_fn(void *arg)
 {
     MttcgForceRcuNotifier force_rcu;
     CPUState *cpu = arg;
@@ -137,23 +137,3 @@  void mttcg_kick_vcpu_thread(CPUState *cpu)
 {
     cpu_exit(cpu);
 }
-
-void mttcg_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_new0(QemuThread, 1);
-    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
-    qemu_cond_init(cpu->halt_cond);
-
-    /* create a thread per vCPU with TCG (MTTCG) */
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
-             cpu->cpu_index);
-
-    qemu_thread_create(cpu->thread, thread_name, mttcg_cpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-
-#ifdef _WIN32
-    cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
-}
diff --git a/accel/tcg/tcg-accel-ops-mttcg.h b/accel/tcg/tcg-accel-ops-mttcg.h
index 9fdc5a2ab5..b61aff5c1d 100644
--- a/accel/tcg/tcg-accel-ops-mttcg.h
+++ b/accel/tcg/tcg-accel-ops-mttcg.h
@@ -13,7 +13,6 @@ 
 /* kick MTTCG vCPU thread */
 void mttcg_kick_vcpu_thread(CPUState *cpu);
 
-/* start an mttcg vCPU thread */
-void mttcg_start_vcpu_thread(CPUState *cpu);
+void *mttcg_vcpu_thread_fn(void *arg);
 
 #endif /* TCG_CPUS_MTTCG_H */
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 3da684b8e6..006b787289 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -148,7 +148,7 @@  static void rr_force_rcu(Notifier *notify, void *data)
  * elsewhere.
  */
 
-static void *rr_cpu_thread_fn(void *arg)
+void *rr_vcpu_thread_fn(void *arg)
 {
     Notifier force_rcu;
     CPUState *cpu = arg;
@@ -279,28 +279,13 @@  bool rr_create_vcpu_thread_precheck(CPUState *cpu)
     return !single_tcg_cpu_thread;
 }
 
-void rr_start_vcpu_thread(CPUState *cpu)
+void rr_create_vcpu_thread_postcheck(CPUState *cpu)
 {
-    char thread_name[VCPU_THREAD_NAME_SIZE];
     static QemuCond *single_tcg_halt_cond;
-    static QemuThread *single_tcg_cpu_thread;
-
-    if (!single_tcg_cpu_thread) {
-        cpu->thread = g_new0(QemuThread, 1);
-        cpu->halt_cond = g_new0(QemuCond, 1);
-        qemu_cond_init(cpu->halt_cond);
-
-        /* share a single thread for all cpus with TCG */
-        snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "ALL CPUs/TCG");
-        qemu_thread_create(cpu->thread, thread_name,
-                           rr_cpu_thread_fn,
-                           cpu, QEMU_THREAD_JOINABLE);
 
+    if (! single_tcg_cpu_thread) {
         single_tcg_halt_cond = cpu->halt_cond;
         single_tcg_cpu_thread = cpu->thread;
-#ifdef _WIN32
-        cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
     } else {
         /* we share the thread */
         cpu->thread = single_tcg_cpu_thread;
diff --git a/accel/tcg/tcg-accel-ops-rr.h b/accel/tcg/tcg-accel-ops-rr.h
index e2273b66d4..a1e75e7afb 100644
--- a/accel/tcg/tcg-accel-ops-rr.h
+++ b/accel/tcg/tcg-accel-ops-rr.h
@@ -16,7 +16,9 @@ 
 void rr_kick_vcpu_thread(CPUState *unused);
 
 bool rr_create_vcpu_thread_precheck(CPUState *cpu);
-/* start the round robin vcpu thread */
-void rr_start_vcpu_thread(CPUState *cpu);
+void rr_create_vcpu_thread_postcheck(CPUState *cpu);
+bool rr_destroy_vcpu_thread_precheck(CPUState *cpu);
+
+void *rr_vcpu_thread_fn(void *arg);
 
 #endif /* TCG_CPUS_RR_H */
diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c
index d2181ea1e5..127dd6fee5 100644
--- a/accel/tcg/tcg-accel-ops.c
+++ b/accel/tcg/tcg-accel-ops.c
@@ -95,11 +95,13 @@  void tcg_handle_interrupt(CPUState *cpu, int mask)
 static void tcg_accel_ops_init(AccelOpsClass *ops)
 {
     if (qemu_tcg_mttcg_enabled()) {
-        ops->create_vcpu_thread = mttcg_start_vcpu_thread;
+        ops->vcpu_thread_fn = mttcg_vcpu_thread_fn;
         ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
         ops->handle_interrupt = tcg_handle_interrupt;
     } else {
-        ops->create_vcpu_thread = rr_start_vcpu_thread;
+        ops->vcpu_thread_fn = rr_vcpu_thread_fn;
+        ops->create_vcpu_thread_precheck = rr_create_vcpu_thread_precheck;
+        ops->create_vcpu_thread_postcheck = rr_create_vcpu_thread_postcheck;
         ops->kick_vcpu_thread = rr_kick_vcpu_thread;
 
         if (icount_enabled()) {
diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c
index 69aa7d018b..ef40f626e2 100644
--- a/accel/xen/xen-all.c
+++ b/accel/xen/xen-all.c
@@ -219,7 +219,7 @@  static void xen_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = dummy_start_vcpu_thread;
+    ops->vcpu_thread_fn = dummy_vcpu_thread_fn;
 }
 
 static const TypeInfo xen_accel_ops_type = {
diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h
index 26b542d35c..caf337f61f 100644
--- a/include/sysemu/accel-ops.h
+++ b/include/sysemu/accel-ops.h
@@ -30,7 +30,8 @@  struct AccelOpsClass {
 
     bool (*cpus_are_resettable)(void);
 
-    void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY NON-NULL */
+    const char *thread_name;
+    void *(*vcpu_thread_fn)(void *arg); /* MANDATORY NON-NULL */
     /* If non-NULL, return whether common vCPU thread must be created */
     bool (*create_vcpu_thread_precheck)(CPUState *cpu);
     void (*create_vcpu_thread_postcheck)(CPUState *cpu);
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index b5c87d48b3..bf5629c58f 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -9,8 +9,8 @@  void cpus_register_accel(const AccelOpsClass *i);
 
 /* accel/dummy-cpus.c */
 
-/* Create a dummy vcpu for AccelOpsClass->create_vcpu_thread */
-void dummy_start_vcpu_thread(CPUState *);
+/* Create a dummy vcpu for AccelOpsClass->vcpu_thread_fn */
+void *dummy_vcpu_thread_fn(void *arg);
 
 /* interface available for cpus accelerator threads */
 
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 857e2081ba..cf430ac486 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -601,6 +601,22 @@  void resume_all_vcpus(void)
     }
 }
 
+static void common_vcpu_thread_create(CPUState *cpu)
+{
+    char thread_name[VCPU_THREAD_NAME_SIZE];
+
+    cpu->thread = g_new0(QemuThread, 1);
+    cpu->halt_cond = g_new0(QemuCond, 1);
+    qemu_cond_init(cpu->halt_cond);
+    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/%s",
+             cpu->cpu_index, cpus_accel->thread_name ?: "DUMMY");
+    qemu_thread_create(cpu->thread, thread_name, cpus_accel->vcpu_thread_fn,
+                       cpu, QEMU_THREAD_JOINABLE);
+#ifdef _WIN32
+    cpu->hThread = qemu_thread_get_handle(cpu->thread);
+#endif
+}
+
 void cpu_remove_sync(CPUState *cpu)
 {
     cpu->stop = true;
@@ -614,7 +630,7 @@  void cpu_remove_sync(CPUState *cpu)
 void cpus_register_accel(const AccelOpsClass *ops)
 {
     assert(ops != NULL);
-    assert(ops->create_vcpu_thread != NULL); /* mandatory */
+    assert(ops->vcpu_thread_fn != NULL); /* mandatory */
     cpus_accel = ops;
 }
 
@@ -636,10 +652,11 @@  void qemu_init_vcpu(CPUState *cpu)
     }
 
     /* accelerators all implement the AccelOpsClass */
-    g_assert(cpus_accel != NULL && cpus_accel->create_vcpu_thread != NULL);
+    g_assert(cpus_accel != NULL && cpus_accel->vcpu_thread_fn != NULL);
+
     if (cpus_accel->create_vcpu_thread_precheck == NULL
             || cpus_accel->create_vcpu_thread_precheck(cpu)) {
-        cpus_accel->create_vcpu_thread(cpu);
+        common_vcpu_thread_create(cpu);
     }
     if (cpus_accel->create_vcpu_thread_postcheck) {
         cpus_accel->create_vcpu_thread_postcheck(cpu);
diff --git a/target/i386/hax/hax-accel-ops.c b/target/i386/hax/hax-accel-ops.c
index 18114fe34d..2fc2a9b8a4 100644
--- a/target/i386/hax/hax-accel-ops.c
+++ b/target/i386/hax/hax-accel-ops.c
@@ -57,28 +57,12 @@  static void *hax_cpu_thread_fn(void *arg)
     return NULL;
 }
 
-static void hax_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_new0(QemuThread, 1);
-    cpu->halt_cond = g_new0(QemuCond, 1);
-    qemu_cond_init(cpu->halt_cond);
-
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HAX",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, hax_cpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-#ifdef _WIN32
-    cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
-}
-
 static void hax_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = hax_start_vcpu_thread;
+    ops->thread_name = "HAX";
+    ops->vcpu_thread_fn = hax_cpu_thread_fn;
     ops->kick_vcpu_thread = hax_kick_vcpu_thread;
 
     ops->synchronize_post_reset = hax_cpu_synchronize_post_reset;
diff --git a/target/i386/nvmm/nvmm-accel-ops.c b/target/i386/nvmm/nvmm-accel-ops.c
index 6c46101ac1..a6dc73aa35 100644
--- a/target/i386/nvmm/nvmm-accel-ops.c
+++ b/target/i386/nvmm/nvmm-accel-ops.c
@@ -60,19 +60,6 @@  static void *qemu_nvmm_cpu_thread_fn(void *arg)
     return NULL;
 }
 
-static void nvmm_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_new0(QemuThread, 1);
-    cpu->halt_cond = g_new0(QemuCond, 1);
-    qemu_cond_init(cpu->halt_cond);
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/NVMM",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, qemu_nvmm_cpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-}
-
 /*
  * Abort the call to run the virtual processor by another thread, and to
  * return the control to that thread.
@@ -87,7 +74,9 @@  static void nvmm_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = nvmm_start_vcpu_thread;
+    ops->thread_name = "NVMM";
+    ops->vcpu_thread_fn = qemu_nvmm_cpu_thread_fn;
+
     ops->kick_vcpu_thread = nvmm_kick_vcpu_thread;
 
     ops->synchronize_post_reset = nvmm_cpu_synchronize_post_reset;
diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c
index dd2a9f7657..6498eb2060 100644
--- a/target/i386/whpx/whpx-accel-ops.c
+++ b/target/i386/whpx/whpx-accel-ops.c
@@ -60,22 +60,6 @@  static void *whpx_cpu_thread_fn(void *arg)
     return NULL;
 }
 
-static void whpx_start_vcpu_thread(CPUState *cpu)
-{
-    char thread_name[VCPU_THREAD_NAME_SIZE];
-
-    cpu->thread = g_new0(QemuThread, 1);
-    cpu->halt_cond = g_new0(QemuCond, 1);
-    qemu_cond_init(cpu->halt_cond);
-    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/WHPX",
-             cpu->cpu_index);
-    qemu_thread_create(cpu->thread, thread_name, whpx_cpu_thread_fn,
-                       cpu, QEMU_THREAD_JOINABLE);
-#ifdef _WIN32
-    cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
-}
-
 static void whpx_kick_vcpu_thread(CPUState *cpu)
 {
     if (!qemu_cpu_is_self(cpu)) {
@@ -92,7 +76,9 @@  static void whpx_accel_ops_class_init(ObjectClass *oc, void *data)
 {
     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
 
-    ops->create_vcpu_thread = whpx_start_vcpu_thread;
+    ops->thread_name = "WHPX";
+    ops->vcpu_thread_fn = whpx_cpu_thread_fn;
+
     ops->kick_vcpu_thread = whpx_kick_vcpu_thread;
     ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle;