For some scenarios, it needs to hot-add a monitor device. But QEMU doesn't support hotplug yet. It also works by adding a monitor with null backend by default and then change its backend to socket by QMP command "chardev-change".
So this patch is to support monitor chardev hotswap with QMP. Signed-off-by: Li Zhang <li.zh...@cloud.ionos.com> Reviewed-by: Pankaj Gupta <pankaj.gu...@ionos.com> --- v1 -> v2: - Change mutex lock mon_lock section - Fix indentation problems monitor/monitor-internal.h | 3 +++ monitor/monitor.c | 2 +- monitor/qmp.c | 43 +++++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 9c3a09cb01..1b80c74883 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -183,4 +183,7 @@ void help_cmd(Monitor *mon, const char *name); void handle_hmp_command(MonitorHMP *mon, const char *cmdline); int hmp_compare_cmd(const char *name, const char *list); +gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque); + #endif diff --git a/monitor/monitor.c b/monitor/monitor.c index 636bcc81c5..16a3620d02 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -157,7 +157,7 @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) static void monitor_flush_locked(Monitor *mon); -static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, +gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, void *opaque) { Monitor *mon = opaque; diff --git a/monitor/qmp.c b/monitor/qmp.c index 2b0308f933..5fa65401ae 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -44,6 +44,7 @@ struct QMPRequest { Error *err; }; typedef struct QMPRequest QMPRequest; +static void monitor_qmp_set_handlers_bh(void *opaque); QmpCommandList qmp_commands, qmp_cap_negotiation_commands; @@ -477,7 +478,36 @@ void monitor_data_destroy_qmp(MonitorQMP *mon) g_queue_free(mon->qmp_requests); } -static void monitor_qmp_setup_handlers_bh(void *opaque) +static int monitor_qmp_change(void *opaque) +{ + MonitorQMP *mon = opaque; + + mon->common.use_io_thread = qemu_chr_has_feature(mon->common.chr.chr, + QEMU_CHAR_FEATURE_GCONTEXT); + + if (mon->common.use_io_thread) { + aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), + monitor_qmp_set_handlers_bh, mon); + } else { + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, + monitor_qmp_read, monitor_qmp_event, + monitor_qmp_change, &mon->common, NULL, true); + } + + qemu_mutex_lock(&mon->common.mon_lock); + if (mon->common.out_watch) { + g_source_remove(mon->common.out_watch); + mon->common.out_watch = qemu_chr_fe_add_watch(&mon->common.chr, + G_IO_OUT | G_IO_HUP, + monitor_unblocked, + &mon->common); + } + qemu_mutex_unlock(&mon->common.mon_lock); + + return 0; +} + +static void monitor_qmp_set_handlers_bh(void *opaque) { MonitorQMP *mon = opaque; GMainContext *context; @@ -487,7 +517,14 @@ static void monitor_qmp_setup_handlers_bh(void *opaque) assert(context); qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_qmp_read, monitor_qmp_event, - NULL, &mon->common, context, true); + monitor_qmp_change, &mon->common, context, true); + +} + +static void monitor_qmp_setup_handlers_bh(void *opaque) +{ + MonitorQMP *mon = opaque; + monitor_qmp_set_handlers_bh(mon); monitor_list_append(&mon->common); } @@ -528,7 +565,7 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) } else { qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_qmp_read, monitor_qmp_event, - NULL, &mon->common, NULL, true); + monitor_qmp_change, &mon->common, NULL, true); monitor_list_append(&mon->common); } } -- 2.25.1