[PATCH v20 10/21] virtio-gpu: Bounce virtio_gpu_ctrl_bh() to main-loop thread

Dmitry Osipenko posted 21 patches 11 hours ago
Maintainers: Pierrick Bouvier <pierrick.bouvier@linaro.org>, "Michael S. Tsirkin" <mst@redhat.com>, "Alex Bennée" <alex.bennee@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Dmitry Osipenko <dmitry.osipenko@collabora.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
[PATCH v20 10/21] virtio-gpu: Bounce virtio_gpu_ctrl_bh() to main-loop thread
Posted by Dmitry Osipenko 11 hours ago
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: qemu-stable@nongnu.org
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 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
Re: [PATCH v20 10/21] virtio-gpu: Bounce virtio_gpu_ctrl_bh() to main-loop thread
Posted by Akihiko Odaki 2 hours ago
On 2026/03/02 5:48, Dmitry Osipenko wrote:
> 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.

I think you can make use of iohandler_get_aio_context() instead of bouncing.

Regards,
Akihiko Odaki

> 
>   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>
> ---
>   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 {