From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org, Eduardo Habkost <ehabkost@redhat.com>,
Juan Quintela <quintela@redhat.com>,
Eric Blake <eblake@redhat.com>, Cleber Rosa <crosa@redhat.com>,
Markus Armbruster <armbru@redhat.com>,
Gerd Hoffmann <kraxel@redhat.com>,
Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
Date: Thu, 12 Apr 2018 15:48:15 +0100 [thread overview]
Message-ID: <20180412144814.GH2704@work-vm> (raw)
In-Reply-To: <20180326150916.9602-36-marcandre.lureau@redhat.com>
* Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
> Make screendump asynchronous to provide correct screendumps.
>
> HMP doesn't have async support, so it has to remain synchronous and
> potentially incorrect to avoid potential races.
>
> Fixes:
> https://bugzilla.redhat.com/show_bug.cgi?id=1230527
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Hi,
Looking at this and the previous pair of patches, I think we'd be
better if we defined that async commands took a callback function
pointer and data that they call.
Here we've got 'graphic_hw_update_done' that explicitly walks qmp
lists; but I think it's better just to pass graphic_hw_update() the
completion data together with a callback function and it calls that when
it's done.
(Also isn't it a little bit of a race, calling graphic_hw_update() and
*then* adding the entry to the list? Can't it end up calling the _done()
before we've added it to the list).
Also, do we need a list of outstanding screendumps, or should we just
have a list of async commands.
It wouldn't seem hard to use the async-QMP command from the HMP
and then just provide a way to tell whether it had finished.
Dave
> ---
> qapi/ui.json | 3 +-
> include/ui/console.h | 3 ++
> hmp.c | 2 +-
> ui/console.c | 99 ++++++++++++++++++++++++++++++++++++++++----
> 4 files changed, 96 insertions(+), 11 deletions(-)
>
> diff --git a/qapi/ui.json b/qapi/ui.json
> index 5d01ad4304..4d2c326fb9 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -96,7 +96,8 @@
> #
> ##
> { 'command': 'screendump',
> - 'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
> + 'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
> + 'async': true }
>
> ##
> # == Spice
> diff --git a/include/ui/console.h b/include/ui/console.h
> index fc21621656..0c02190963 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -74,6 +74,9 @@ struct MouseTransformInfo {
> };
>
> void hmp_mouse_set(Monitor *mon, const QDict *qdict);
> +void hmp_screendump_sync(const char *filename,
> + bool has_device, const char *device,
> + bool has_head, int64_t head, Error **errp);
>
> /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
> constants) */
> diff --git a/hmp.c b/hmp.c
> index 679467d85a..da9008fe63 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -2144,7 +2144,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
> int64_t head = qdict_get_try_int(qdict, "head", 0);
> Error *err = NULL;
>
> - qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
> + hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err);
> hmp_handle_error(mon, &err);
> }
>
> diff --git a/ui/console.c b/ui/console.c
> index 29234605a7..da51861191 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -32,6 +32,7 @@
> #include "chardev/char-fe.h"
> #include "trace.h"
> #include "exec/memory.h"
> +#include "monitor/monitor.h"
>
> #define DEFAULT_BACKSCROLL 512
> #define CONSOLE_CURSOR_PERIOD 500
> @@ -116,6 +117,12 @@ typedef enum {
> TEXT_CONSOLE_FIXED_SIZE
> } console_type_t;
>
> +struct qmp_screendump {
> + gchar *filename;
> + QmpReturn *ret;
> + QLIST_ENTRY(qmp_screendump) link;
> +};
> +
> struct QemuConsole {
> Object parent;
>
> @@ -165,6 +172,8 @@ struct QemuConsole {
> QEMUFIFO out_fifo;
> uint8_t out_fifo_buf[16];
> QEMUTimer *kbd_timer;
> +
> + QLIST_HEAD(, qmp_screendump) qmp_screendumps;
> };
>
> struct DisplayState {
> @@ -190,6 +199,8 @@ static void dpy_refresh(DisplayState *s);
> static DisplayState *get_alloc_displaystate(void);
> static void text_console_update_cursor_timer(void);
> static void text_console_update_cursor(void *opaque);
> +static void ppm_save(const char *filename, DisplaySurface *ds,
> + Error **errp);
>
> static void gui_update(void *opaque)
> {
> @@ -256,8 +267,42 @@ static void gui_setup_refresh(DisplayState *ds)
> ds->have_text = have_text;
> }
>
> +static void qmp_screendump_finish(QemuConsole *con, const char *filename,
> + QmpReturn *ret)
> +{
> + Error *err = NULL;
> + DisplaySurface *surface;
> + Monitor *prev_mon = cur_mon;
> +
> + if (qmp_return_is_cancelled(ret)) {
> + return;
> + }
> +
> + cur_mon = qmp_return_get_monitor(ret);
> + surface = qemu_console_surface(con);
> +
> + /* FIXME: async save with coroutine? it would have to copy or lock
> + * the surface. */
> + ppm_save(filename, surface, &err);
> +
> + if (err) {
> + qmp_return_error(ret, err);
> + } else {
> + qmp_screendump_return(ret);
> + }
> + cur_mon = prev_mon;
> +}
> +
> void graphic_hw_update_done(QemuConsole *con)
> {
> + struct qmp_screendump *dump, *next;
> +
> + QLIST_FOREACH_SAFE(dump, &con->qmp_screendumps, link, next) {
> + qmp_screendump_finish(con, dump->filename, dump->ret);
> + g_free(dump->filename);
> + QLIST_REMOVE(dump, link);
> + g_free(dump);
> + }
> }
>
> bool graphic_hw_update(QemuConsole *con)
> @@ -358,35 +403,70 @@ write_err:
> goto out;
> }
>
> -void qmp_screendump(const char *filename, bool has_device, const char *device,
> - bool has_head, int64_t head, Error **errp)
> +
> +static QemuConsole *get_console(bool has_device, const char *device,
> + bool has_head, int64_t head, Error **errp)
> {
> - QemuConsole *con;
> - DisplaySurface *surface;
> + QemuConsole *con = NULL;
>
> if (has_device) {
> con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
> errp);
> - if (!con) {
> - return;
> - }
> } else {
> if (has_head) {
> error_setg(errp, "'head' must be specified together with 'device'");
> - return;
> + return NULL;
> }
> con = qemu_console_lookup_by_index(0);
> if (!con) {
> error_setg(errp, "There is no console to take a screendump from");
> - return;
> }
> }
>
> + return con;
> +}
> +
> +void hmp_screendump_sync(const char *filename,
> + bool has_device, const char *device,
> + bool has_head, int64_t head, Error **errp)
> +{
> + DisplaySurface *surface;
> + QemuConsole *con = get_console(has_device, device, has_head, head, errp);
> +
> + if (!con) {
> + return;
> + }
> + /* This may not complete the drawing with Spice, you may have
> + * glitches or outdated dumps, use qmp instead! */
> graphic_hw_update(con);
> surface = qemu_console_surface(con);
> ppm_save(filename, surface, errp);
> }
>
> +void qmp_screendump(const char *filename,
> + bool has_device, const char *device,
> + bool has_head, int64_t head,
> + QmpReturn *qret)
> +{
> + Error *err = NULL;
> + bool async;
> + QemuConsole *con = get_console(has_device, device, has_head, head, &err);
> +
> + if (!con) {
> + qmp_return_error(qret, err);
> + return;
> + }
> + async = graphic_hw_update(con);
> + if (async) {
> + struct qmp_screendump *dump = g_new(struct qmp_screendump, 1);
> + dump->filename = g_strdup(filename);
> + dump->ret = qret;
> + QLIST_INSERT_HEAD(&con->qmp_screendumps, dump, link);
> + } else {
> + qmp_screendump_finish(con, filename, qret);
> + }
> +}
> +
> void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
> {
> if (!con) {
> @@ -1280,6 +1360,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
> obj = object_new(TYPE_QEMU_CONSOLE);
> s = QEMU_CONSOLE(obj);
> s->head = head;
> + QLIST_INIT(&s->qmp_screendumps);
> object_property_add_link(obj, "device", TYPE_DEVICE,
> (Object **)&s->device,
> object_property_allow_set_link,
> --
> 2.17.0.rc1.1.g4c4f2b46a3
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
next prev parent reply other threads:[~2018-04-12 14:48 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments Marc-André Lureau
2018-03-26 18:26 ` Eduardo Habkost
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 03/38] Revert "qmp: isolate responses into io thread" Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 04/38] monitor: no need to save need_resume Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 05/38] monitor: further simplify previous patch Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it Marc-André Lureau
2018-03-26 19:31 ` Eric Blake
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL Marc-André Lureau
2018-07-05 11:35 ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times Marc-André Lureau
2018-07-05 11:42 ` Markus Armbruster
2018-07-05 12:17 ` Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser Marc-André Lureau
2018-07-05 11:49 ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests Marc-André Lureau
2018-07-05 11:55 ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
2018-07-05 11:56 ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test Marc-André Lureau
2018-07-05 11:59 ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 13/38] qga: process_event() simplification Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 14/38] monitor: simplify monitor_qmp_respond() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 15/38] qmp: pass and return a QDict to qmp_dispatch() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 16/38] qmp: move 'id' copy " Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 17/38] qmp: constify qmp_is_oob() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 18/38] qmp: add QmpSession Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 19/38] QmpSession: add a return_cb Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 20/38] QmpSession: add json parser and use it in qga Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 21/38] QmpSession: add a dispatch callback Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 22/38] monitor: use QmpSession parsing and common dispatch code Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 23/38] QmpSession: introduce QmpReturn Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 24/38] qmp: remove qmp_build_error_object() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 26/38] qmp: fold do_qmp_dispatch() in qmp_dispatch() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 27/38] QmpSession: keep a queue of pending commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous Marc-André Lureau
2018-04-12 14:48 ` Dr. David Alan Gilbert [this message]
2018-04-19 16:05 ` Marc-André Lureau
2019-04-09 14:06 ` Marc-André Lureau
2019-04-09 14:06 ` Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches Marc-André Lureau
2018-03-26 17:24 ` [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Dr. David Alan Gilbert
2018-03-26 17:30 ` Marc-André Lureau
2018-03-26 17:43 ` no-reply
2018-03-26 17:55 ` no-reply
2018-04-04 9:34 ` Stefan Hajnoczi
2018-04-04 10:01 ` Marc-André Lureau
2018-04-04 13:45 ` Eric Blake
2018-04-04 13:57 ` Marc-André Lureau
2018-07-05 13:05 ` 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=20180412144814.GH2704@work-vm \
--to=dgilbert@redhat.com \
--cc=armbru@redhat.com \
--cc=crosa@redhat.com \
--cc=eblake@redhat.com \
--cc=ehabkost@redhat.com \
--cc=kraxel@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=quintela@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.