diff --git a/chardev/char-io.c b/chardev/char-io.c index 3be17b51ca..beac5cd245 100644 --- a/chardev/char-io.c +++ b/chardev/char-io.c @@ -182,3 +182,11 @@ int io_channel_send(QIOChannel *ioc, const void *buf, size_t len) { return io_channel_send_full(ioc, buf, len, NULL, 0); } + +void remove_listener_fd_in_watch(Chardev *chr) +{ + ChardevClass *cc = CHARDEV_GET_CLASS(chr); + if (cc->chr_listener_cleanup) { + cc->chr_listener_cleanup(chr); + } +} diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 26d2f11202..3f45dd2ecd 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1570,6 +1570,15 @@ char_socket_get_connected(Object *obj, Error **errp) return s->state == TCP_CHARDEV_STATE_CONNECTED; } +static void tcp_chr_listener_cleanup(Chardev *chr) +{ + SocketChardev *s = SOCKET_CHARDEV(chr); + if (s->listener) { + qio_net_listener_set_client_func_full(s->listener, NULL, NULL, + NULL, chr->gcontext); + } +} + static void char_socket_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -1587,6 +1596,7 @@ static void char_socket_class_init(ObjectClass *oc, const void *data) cc->chr_add_client = tcp_chr_add_client; cc->chr_add_watch = tcp_chr_add_watch; cc->chr_update_read_handler = tcp_chr_update_read_handler; + cc->chr_listener_cleanup = tcp_chr_listener_cleanup; object_class_property_add(oc, "addr", "SocketAddress", char_socket_get_addr, NULL, diff --git a/include/chardev/char-io.h b/include/chardev/char-io.h index ac379ea70e..540131346d 100644 --- a/include/chardev/char-io.h +++ b/include/chardev/char-io.h @@ -43,4 +43,6 @@ int io_channel_send(QIOChannel *ioc, const void *buf, size_t len); int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len, int *fds, size_t nfds); +void remove_listener_fd_in_watch(Chardev *chr); + #endif /* CHAR_IO_H */ diff --git a/include/chardev/char.h b/include/chardev/char.h index b65e9981c1..192cad67d4 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -307,6 +307,8 @@ struct ChardevClass { /* handle various events */ void (*chr_be_event)(Chardev *s, QEMUChrEvent event); + + void (*chr_listener_cleanup)(Chardev *chr); }; Chardev *qemu_chardev_new(const char *id, const char *typename, diff --git a/monitor/qmp.c b/monitor/qmp.c index cb99a12d94..7ae070dc8d 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -537,6 +537,11 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) * e.g. the chardev is in client mode, with wait=on. */ remove_fd_in_watch(chr); + /* + * Clean up listener IO sources early to prevent racy fd + * handling between the main thread and the I/O thread. + */ + remove_listener_fd_in_watch(chr); /* * We can't call qemu_chr_fe_set_handlers() directly here * since chardev might be running in the monitor I/O