QEMU's display GL core is tied to main-loop thread and virtio-gpu
interacts with display while processing GPU commands. virtio_gpu_ctrl_bh()
works in generic AIO context that can be processed from vCPU thread, while
GL and UI toolkits are bound to the main-loop thread. Bounce the ctrl-bh
execution if running from a thread other than main to fix the problem.

 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: [email protected]
Signed-off-by: Dmitry Osipenko <[email protected]>
---
 hw/display/virtio-gpu.c        | 12 +++++++++++-
 include/hw/virtio/virtio-gpu.h |  2 ++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 643e91ca2a7a..d0737cbba8a2 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1126,7 +1126,16 @@ static void virtio_gpu_ctrl_bh(void *opaque)
     VirtIOGPU *g = opaque;
     VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
 
-    vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq);
+    /*
+     * Bounce handling to main-loop thread as display UI toolkit
+     * and GL context are bounded there.
+     */
+    if (qemu_get_thread_id() == g->thread_id) {
+        vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq);
+    } else {
+        aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                virtio_gpu_ctrl_bh, g);
+    }
 }
 
 static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
@@ -1533,6 +1542,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error 
**errp)
     QTAILQ_INIT(&g->reslist);
     QTAILQ_INIT(&g->cmdq);
     QTAILQ_INIT(&g->fenceq);
+    g->thread_id = qemu_get_thread_id();
 }
 
 static void virtio_gpu_device_unrealize(DeviceState *qdev)
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 58e0f91fda65..d3bd8ed0d28a 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -218,6 +218,8 @@ struct VirtIOGPU {
     } dmabuf;
 
     GArray *capset_ids;
+
+    int thread_id;
 };
 
 struct VirtIOGPUClass {
-- 
2.52.0


Reply via email to