Commit 235f9b3638 for qemu.org
commit 235f9b36383e4cc7a790bca51eddbe38edd5438c
Author: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Date: Wed Mar 4 16:50:31 2026 +0000
virtio-gpu: Ensure BHs are invoked only from main-loop thread
QEMU's display GL core is tied to main-loop thread and virtio-gpu
interacts with display while processing GPU commands. Virtio-gpu BHs
work in generic AIO context that can be invoked on vCPU thread, while
GL and UI toolkits are bound to the main-loop thread.
Make virtio-gpu BHs use iohandler AIO context that is handled in a
main-loop thread only.
0 SDL_GL_MakeCurrent() (libSDL3)
1 SDL_GL_MakeCurrent_REAL() (libSDL2)
2 sdl2_gl_make_context_current() (ui/sdl2-gl.c:201)
3 make_current() (virglrenderer.c:639)
4 vrend_finish_context_switch() (vrend_renderer.c:11630)
5 vrend_hw_switch_context() (vrend_renderer.c:11613)
6 vrend_renderer_force_ctx_0() (vrend_renderer.c:12986)
7 virgl_renderer_force_ctx_0() (virglrenderer.c:460)
8 virtio_gpu_virgl_process_cmd() (virtio-gpu-virgl.c:1013)
9 virtio_gpu_process_cmdq() (virtio-gpu.c:1050)
10 virtio_gpu_gl_handle_ctrl() (virtio-gpu-gl.c:86)
11 aio_bh_poll() (util/async.c)
12 aio_poll() (util/aio-posix.c)
13 blk_pwrite() (block/block-gen.c:1985)
14 pflash_update() (pflash_cfi01.c:396)
15 pflash_write() (pflash_cfi01.c:541)
16 memory_region_dispatch_write() (system/memory.c:1554)
17 flatview_write() (system/physmem.c:3333)
18 address_space_write() (system/physmem.c:3453)
19 kvm_cpu_exec() (accel/kvm/kall-all.c:3248)
20 kvm_vcpu_thread_fn() (accel/kvm/kaccel-ops.c:53)
Cc: qemu-stable@nongnu.org
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Message-ID: <20260303151422.977399-8-dmitry.osipenko@collabora.com>
Message-ID: <20260304165043.1437519-10-alex.bennee@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 0f754829fb..10c4b5160f 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -1203,9 +1203,9 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
}
#if VIRGL_VERSION_MAJOR >= 1
- gl->cmdq_resume_bh = aio_bh_new(qemu_get_aio_context(),
- virtio_gpu_virgl_resume_cmdq_bh,
- g);
+ gl->cmdq_resume_bh = virtio_bh_io_new_guarded(DEVICE(g),
+ virtio_gpu_virgl_resume_cmdq_bh,
+ g);
#endif
return 0;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index b2af861f0d..a89d49aa8c 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1526,9 +1526,9 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
g->ctrl_vq = virtio_get_queue(vdev, 0);
g->cursor_vq = virtio_get_queue(vdev, 1);
- g->ctrl_bh = virtio_bh_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
- g->cursor_bh = virtio_bh_new_guarded(qdev, virtio_gpu_cursor_bh, g);
- g->reset_bh = qemu_bh_new(virtio_gpu_reset_bh, g);
+ g->ctrl_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
+ g->cursor_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_cursor_bh, g);
+ g->reset_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_reset_bh, g);
qemu_cond_init(&g->reset_cond);
QTAILQ_INIT(&g->reslist);
QTAILQ_INIT(&g->cmdq);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 22d798e6cd..4c5a4479bf 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4497,3 +4497,13 @@ QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
return qemu_bh_new_full(cb, opaque, name,
&transport->mem_reentrancy_guard);
}
+
+QEMUBH *virtio_bh_io_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name)
+{
+ DeviceState *transport = qdev_get_parent_bus(dev)->parent;
+
+ return aio_bh_new_full(iohandler_get_aio_context(), cb, opaque, name,
+ &transport->mem_reentrancy_guard);
+}
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 42d2089939..6344bd7b68 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -552,4 +552,14 @@ QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
#define virtio_bh_new_guarded(dev, cb, opaque) \
virtio_bh_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
+/*
+ * The "_io" variant runs BH only on a main-loop thread, while generic BH
+ * may run on a vCPU thread.
+ */
+QEMUBH *virtio_bh_io_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name);
+#define virtio_bh_io_new_guarded(dev, cb, opaque) \
+ virtio_bh_io_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
+
#endif