console: make QMP/HMP screendump run in coroutine
Thanks to the monitors' coroutine support (merge commit b7092cda1b
),
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>
This commit is contained in:
parent
d00ec2fe86
commit
0d9b90ce5c
@ -254,6 +254,7 @@ ERST
|
||||
.help = "save screen from head 'head' of display device 'device' "
|
||||
"into PPM image 'filename'",
|
||||
.cmd = hmp_screendump,
|
||||
.coroutine = true,
|
||||
},
|
||||
|
||||
SRST
|
||||
|
@ -1762,7 +1762,8 @@ err_out:
|
||||
goto out;
|
||||
}
|
||||
|
||||
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
||||
void coroutine_fn
|
||||
hmp_screendump(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *filename = qdict_get_str(qdict, "filename");
|
||||
const char *id = qdict_get_try_str(qdict, "device");
|
||||
|
@ -98,7 +98,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'screendump',
|
||||
'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
|
||||
'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
|
||||
'coroutine': true }
|
||||
|
||||
##
|
||||
# == Spice
|
||||
|
32
ui/console.c
32
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,
|
||||
|
Loading…
Reference in New Issue
Block a user