The monitor_qmp_can_read (as a callback of qemu_chr_fe_set_handlers) should return size of buffer which monitor_qmp_read can process. Currently, monitor_can_read returns 1, because it guarantees that only one QMP command can be handled at a time. Thus, for each QMP command, len(QMD) iterations of the main loop are required to handle a command.
This patch adds an input buffer to speed up reading and to keep the guarantee of executing one command at a time. Signed-off-by: Yury Kotov <yury-ko...@yandex-team.ru> --- monitor/monitor-internal.h | 11 +++++++++++ monitor/monitor.c | 27 +++++++++++++++++++++++++++ monitor/qmp.c | 17 +++++++++++++++-- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index c0ba29abf1..22983b9dda 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -32,6 +32,8 @@ #include "qemu/readline.h" #include "sysemu/iothread.h" +#define MON_INPUT_BUFFER_SIZE 1024 + /* * Supported types: * @@ -93,6 +95,11 @@ struct Monitor { gchar *mon_cpu_path; QTAILQ_ENTRY(Monitor) entry; + /* Must be accessed only by monitor's iothread */ + char inbuf[MON_INPUT_BUFFER_SIZE]; + int inbuf_pos; + int inbuf_len; + /* * The per-monitor lock. We can't access guest memory when holding * the lock. @@ -169,9 +176,13 @@ void monitor_data_destroy(Monitor *mon); void monitor_list_append(Monitor *mon); void monitor_fdsets_cleanup(void); +void monitor_inbuf_write(Monitor *mon, const char *buf, int size); +int monitor_inbuf_read(Monitor *mon, char *buf, int size); + void qmp_send_response(MonitorQMP *mon, const QDict *rsp); void monitor_data_destroy_qmp(MonitorQMP *mon); void monitor_qmp_bh_dispatcher(void *data); +void monitor_qmp_handle_inbuf(Monitor *mon); int get_monitor_def(int64_t *pval, const char *name); void help_cmd(Monitor *mon, const char *name); diff --git a/monitor/monitor.c b/monitor/monitor.c index d25cc8ea4a..9eb258ac2f 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -440,6 +440,29 @@ static gboolean qapi_event_throttle_equal(const void *a, const void *b) return TRUE; } +void monitor_inbuf_write(Monitor *mon, const char *buf, int size) +{ + int pos = mon->inbuf_pos + mon->inbuf_len; + + assert(size <= sizeof(mon->inbuf) - mon->inbuf_len); + while (size-- > 0) { + mon->inbuf[pos++ % sizeof(mon->inbuf)] = *buf++; + mon->inbuf_len++; + } +} + +int monitor_inbuf_read(Monitor *mon, char *buf, int size) +{ + int read_bytes = 0; + + while (read_bytes < size && mon->inbuf_len > 0) { + buf[read_bytes++] = mon->inbuf[mon->inbuf_pos++]; + mon->inbuf_pos %= sizeof(mon->inbuf); + mon->inbuf_len--; + } + return read_bytes; +} + int monitor_suspend(Monitor *mon) { if (monitor_is_hmp_non_interactive(mon)) { @@ -465,6 +488,10 @@ static void monitor_accept_input(void *opaque) Monitor *mon = opaque; qemu_chr_fe_accept_input(&mon->chr); + + if (mon->is_qmp) { + monitor_qmp_handle_inbuf(mon); + } } void monitor_resume(Monitor *mon) diff --git a/monitor/qmp.c b/monitor/qmp.c index 37884c6c43..9d2634eeb3 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -315,14 +315,27 @@ static int monitor_qmp_can_read(void *opaque) { Monitor *mon = opaque; - return !atomic_mb_read(&mon->suspend_cnt); + return sizeof(mon->inbuf) - mon->inbuf_len; +} + +void monitor_qmp_handle_inbuf(Monitor *mon) +{ + MonitorQMP *mon_qmp = container_of(mon, MonitorQMP, common); + char ch; + + /* Handle only one byte at a time, because monitor may become suspened */ + while (!atomic_mb_read(&mon->suspend_cnt) && + monitor_inbuf_read(mon, &ch, 1)) { + json_message_parser_feed(&mon_qmp->parser, &ch, 1); + } } static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) { MonitorQMP *mon = opaque; - json_message_parser_feed(&mon->parser, (const char *) buf, size); + monitor_inbuf_write(&mon->common, (const char *)buf, size); + monitor_qmp_handle_inbuf(&mon->common); } static QDict *qmp_greeting(MonitorQMP *mon) -- 2.24.1