From: marcandre.lureau@redhat.com
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
"Gerd Hoffmann" <kraxel@redhat.com>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>
Subject: [PATCH 3/3] console: make QMP/HMP screendump run in coroutine
Date: Sun, 11 Oct 2020 00:41:06 +0400 [thread overview]
Message-ID: <20201010204106.1368710-4-marcandre.lureau@redhat.com> (raw)
In-Reply-To: <20201010204106.1368710-1-marcandre.lureau@redhat.com>
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Thanks to the monitors coroutine support, 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 (thus non-blocking).
Potentially, during non-blocking write, some new graphic update could
happen, and thus the image may have some glitches. Whether that
behaviour is acceptable is discutable. Allocating new memory may not be
a good idea, as framebuffers can be quite large. Even then, QEMU may
become less responsive as it requires paging in etc.
Related to:
https://bugzilla.redhat.com/show_bug.cgi?id=1230527
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hmp-commands.hx | 1 +
monitor/hmp-cmds.c | 3 ++-
qapi/ui.json | 3 ++-
ui/console.c | 27 ++++++++++++++++++++++++---
4 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index cd068389de..ff2d7aa8f3 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -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
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 9789f4277f..91608bac6d 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1756,7 +1756,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");
diff --git a/qapi/ui.json b/qapi/ui.json
index 9d6721037f..6c7b33cb72 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -98,7 +98,8 @@
#
##
{ 'command': 'screendump',
- 'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
+ 'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
+ 'coroutine': true }
##
# == Spice
diff --git a/ui/console.c b/ui/console.c
index a56fe0dd26..0118f70d9a 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,15 @@ 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 BQL taken, 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 +398,9 @@ 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 +1317,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,
--
2.28.0
next prev parent reply other threads:[~2020-10-10 20:50 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-10 20:41 [PATCH 0/3] console: make QMP screendump use coroutine marcandre.lureau
2020-10-10 20:41 ` [PATCH 1/3] coroutine: let CoQueue wake up outside a coroutine marcandre.lureau
2020-10-27 6:42 ` Markus Armbruster
2020-10-27 10:34 ` Kevin Wolf
2020-10-10 20:41 ` [PATCH 2/3] console: modify ppm_save to take a pixman image ref marcandre.lureau
2020-10-27 7:27 ` Markus Armbruster
2020-10-10 20:41 ` marcandre.lureau [this message]
2020-10-27 8:41 ` [PATCH 3/3] console: make QMP/HMP screendump run in coroutine Markus Armbruster
2020-10-27 12:07 ` Marc-André Lureau
2020-10-27 14:14 ` Markus Armbruster
2020-10-13 10:50 ` [PATCH 0/3] console: make QMP screendump use coroutine Gerd Hoffmann
2020-10-27 15:37 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201010204106.1368710-4-marcandre.lureau@redhat.com \
--to=marcandre.lureau@redhat.com \
--cc=armbru@redhat.com \
--cc=dgilbert@redhat.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).