diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2020-10-27 17:36:02 +0400 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2020-11-04 08:02:25 +0100 |
commit | 0d9b90ce5c73505648909a89bcd5272081b9c348 (patch) | |
tree | 86b4ec4af40cdb56870e03a81a97cdc18d85086e /ui | |
parent | d00ec2fe86e141324c26816c5847f425a63f851d (diff) |
console: make QMP/HMP screendump run in coroutine
Thanks to the monitors' coroutine support (merge commit b7092cda1b3),
the screendump handler can trigger a graphic_hw_update(), yield and let
the main loop run until update is done. Then the handler is resumed, and
ppm_save() will write the screen image to disk in the coroutine context.
The IO is still blocking though, as the file is set blocking so far,
this could be addressed by some future change (with other caveats).
Related to:
https://bugzilla.redhat.com/show_bug.cgi?id=1230527
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-id: 20201027133602.3038018-4-marcandre.lureau@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'ui')
-rw-r--r-- | ui/console.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/ui/console.c b/ui/console.c index 96dd212a5d..e8e59707d3 100644 --- a/ui/console.c +++ b/ui/console.c @@ -168,6 +168,7 @@ struct QemuConsole { QEMUFIFO out_fifo; uint8_t out_fifo_buf[16]; QEMUTimer *kbd_timer; + CoQueue dump_queue; QTAILQ_ENTRY(QemuConsole) next; }; @@ -263,6 +264,7 @@ static void gui_setup_refresh(DisplayState *ds) void graphic_hw_update_done(QemuConsole *con) { + qemu_co_queue_restart_all(&con->dump_queue); } void graphic_hw_update(QemuConsole *con) @@ -340,8 +342,15 @@ static bool ppm_save(int fd, pixman_image_t *image, Error **errp) return true; } -void qmp_screendump(const char *filename, bool has_device, const char *device, - bool has_head, int64_t head, Error **errp) +static void graphic_hw_update_bh(void *con) +{ + graphic_hw_update(con); +} + +/* Safety: coroutine-only, concurrent-coroutine safe, main thread only */ +void coroutine_fn +qmp_screendump(const char *filename, bool has_device, const char *device, + bool has_head, int64_t head, Error **errp) { g_autoptr(pixman_image_t) image = NULL; QemuConsole *con; @@ -366,7 +375,18 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, } } - graphic_hw_update(con); + if (qemu_co_queue_empty(&con->dump_queue)) { + /* Defer the update, it will restart the pending coroutines */ + aio_bh_schedule_oneshot(qemu_get_aio_context(), + graphic_hw_update_bh, con); + } + qemu_co_queue_wait(&con->dump_queue, NULL); + + /* + * All pending coroutines are woken up, while the BQL is held. No + * further graphic update are possible until it is released. Take + * an image ref before that. + */ surface = qemu_console_surface(con); if (!surface) { error_setg(errp, "no surface"); @@ -381,6 +401,11 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, return; } + /* + * The image content could potentially be updated as the coroutine + * yields and releases the BQL. It could produce corrupted dump, but + * it should be otherwise safe. + */ if (!ppm_save(fd, image, errp)) { qemu_unlink(filename); } @@ -1297,6 +1322,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, obj = object_new(TYPE_QEMU_CONSOLE); s = QEMU_CONSOLE(obj); + qemu_co_queue_init(&s->dump_queue); s->head = head; object_property_add_link(obj, "device", TYPE_DEVICE, (Object **)&s->device, |