From 2b61bb716cd45ffe10fc92512b6134084c0ffcde Mon Sep 17 00:00:00 2001 From: Li Feng Date: Fri, 22 May 2020 10:55:54 +0800 Subject: [PATCH 1/8] char-socket: initialize reconnect timer only when the timer doesn't start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 ) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 ) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 ) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 ) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng Acked-by: Marc-André Lureau Message-Id: <20200522025554.41063-1-fengli@smartx.com> --- chardev/char-socket.c | 2 +- tests/test-char.c | 73 +++++++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 5758d9900f..320aa7c642 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -490,7 +490,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr) if (emit_close) { qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } - if (s->reconnect_time) { + if (s->reconnect_time && !s->reconnect_timer) { qemu_chr_socket_restart_timer(chr); } } diff --git a/tests/test-char.c b/tests/test-char.c index 3afc9b1b8d..73ba1cf601 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -625,12 +625,14 @@ static void char_udp_test(void) typedef struct { int event; bool got_pong; + CharBackend *be; } CharSocketTestData; #define SOCKET_PING "Hello" #define SOCKET_PONG "World" +typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event); static void char_socket_event(void *opaque, QEMUChrEvent event) @@ -639,6 +641,27 @@ char_socket_event(void *opaque, QEMUChrEvent event) data->event = event; } +static void +char_socket_event_with_error(void *opaque, QEMUChrEvent event) +{ + static bool first_error; + CharSocketTestData *data = opaque; + CharBackend *be = data->be; + data->event = event; + switch (event) { + case CHR_EVENT_OPENED: + if (!first_error) { + first_error = true; + qemu_chr_fe_disconnect(be); + } + return; + case CHR_EVENT_CLOSED: + return; + default: + return; + } +} + static void char_socket_read(void *opaque, const uint8_t *buf, int size) @@ -699,19 +722,24 @@ char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, } -static void -char_socket_ping_pong(QIOChannel *ioc) +static int +char_socket_ping_pong(QIOChannel *ioc, Error **errp) { char greeting[sizeof(SOCKET_PING)]; const char *response = SOCKET_PONG; - qio_channel_read_all(ioc, greeting, sizeof(greeting), &error_abort); + int ret; + ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp); + if (ret != 0) { + object_unref(OBJECT(ioc)); + return -1; + } g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0); - qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), &error_abort); - + qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp); object_unref(OBJECT(ioc)); + return 0; } @@ -723,7 +751,7 @@ char_socket_server_client_thread(gpointer data) qio_channel_socket_connect_sync(ioc, addr, &error_abort); - char_socket_ping_pong(QIO_CHANNEL(ioc)); + char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort); return NULL; } @@ -783,6 +811,7 @@ static void char_socket_server_test(gconstpointer opaque) reconnect: data.event = -1; + data.be = &be; qemu_chr_fe_set_handlers(&be, NULL, NULL, char_socket_event, NULL, &data, NULL, true); @@ -855,10 +884,13 @@ char_socket_client_server_thread(gpointer data) QIOChannelSocket *ioc = data; QIOChannelSocket *cioc; +retry: cioc = qio_channel_socket_accept(ioc, &error_abort); g_assert_nonnull(cioc); - char_socket_ping_pong(QIO_CHANNEL(cioc)); + if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) { + goto retry; + } return NULL; } @@ -869,12 +901,13 @@ typedef struct { const char *reconnect; bool wait_connected; bool fd_pass; + char_socket_cb event_cb; } CharSocketClientTestConfig; - static void char_socket_client_test(gconstpointer opaque) { const CharSocketClientTestConfig *config = opaque; + const char_socket_cb event_cb = config->event_cb; QIOChannelSocket *ioc; char *optstr; Chardev *chr; @@ -938,8 +971,9 @@ static void char_socket_client_test(gconstpointer opaque) reconnect: data.event = -1; + data.be = &be; qemu_chr_fe_set_handlers(&be, NULL, NULL, - char_socket_event, NULL, + event_cb, NULL, &data, NULL, true); if (config->reconnect) { g_assert(data.event == -1); @@ -977,7 +1011,7 @@ static void char_socket_client_test(gconstpointer opaque) /* Setup a callback to receive the reply to our greeting */ qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_read, - char_socket_event, NULL, + event_cb, NULL, &data, NULL, true); g_assert(data.event == CHR_EVENT_OPENED); data.event = -1; @@ -1422,17 +1456,20 @@ int main(int argc, char **argv) #define SOCKET_CLIENT_TEST(name, addr) \ static CharSocketClientTestConfig client1 ## name = \ - { addr, NULL, false, false }; \ + { addr, NULL, false, false, char_socket_event}; \ static CharSocketClientTestConfig client2 ## name = \ - { addr, NULL, true, false }; \ + { addr, NULL, true, false, char_socket_event }; \ static CharSocketClientTestConfig client3 ## name = \ - { addr, ",reconnect=1", false }; \ + { addr, ",reconnect=1", false, false, char_socket_event }; \ static CharSocketClientTestConfig client4 ## name = \ - { addr, ",reconnect=1", true }; \ + { addr, ",reconnect=1", true, false, char_socket_event }; \ static CharSocketClientTestConfig client5 ## name = \ - { addr, NULL, false, true }; \ + { addr, NULL, false, true, char_socket_event }; \ static CharSocketClientTestConfig client6 ## name = \ - { addr, NULL, true, true }; \ + { addr, NULL, true, true, char_socket_event }; \ + static CharSocketClientTestConfig client7 ## name = \ + { addr, ",reconnect=1", true, false, \ + char_socket_event_with_error }; \ g_test_add_data_func("/char/socket/client/mainloop/" # name, \ &client1 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ @@ -1444,7 +1481,9 @@ int main(int argc, char **argv) g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ &client5 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ - &client6 ##name, char_socket_client_test) + &client6 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ + &client7 ##name, char_socket_client_test) if (has_ipv4) { SOCKET_SERVER_TEST(tcp, &tcpaddr); From 14a7a203063694ff932f3371ed93e97987dcafc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Jul 2020 22:10:34 +0400 Subject: [PATCH 2/8] chardev: don't abort on attempt to add duplicated chardev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a regression from commit d2623129a7d ("qom: Drop parameter @errp of object_property_add() & friends"). (qemu) chardev-add id=null,backend=null (qemu) chardev-add id=null,backend=null Unexpected error in object_property_try_add() at /home/elmarco/src/qemu/qom/object.c:1166: attempt to add duplicate property 'null' to object (type 'container') That case is currently not covered in the test suite, but will be with the queued patch "char: fix use-after-free with dup chardev & reconnect". Fixes: d2623129a7dec1d3041ad1221dda1ca49c667532 Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster --- chardev/char.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chardev/char.c b/chardev/char.c index e5b43cb4b8..a0626d04d5 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -996,7 +996,11 @@ static Chardev *chardev_new(const char *id, const char *typename, } if (id) { - object_property_add_child(get_chardevs_root(), id, obj); + object_property_try_add_child(get_chardevs_root(), id, obj, + &local_err); + if (local_err) { + goto end; + } object_unref(obj); } From 6806601969a0d6c095e3836423fef1dedec55289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 20 Apr 2020 13:20:12 +0200 Subject: [PATCH 3/8] char: fix use-after-free with dup chardev & reconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a reconnect socket, qemu_char_open() will start a background thread. It should keep a reference on the chardev. Fixes invalid read: READ of size 8 at 0x6040000ac858 thread T7 #0 0x5555598d37b8 in unix_connect_saddr /home/elmarco/src/qq/util/qemu-sockets.c:954 #1 0x5555598d4751 in socket_connect /home/elmarco/src/qq/util/qemu-sockets.c:1109 #2 0x555559707c34 in qio_channel_socket_connect_sync /home/elmarco/src/qq/io/channel-socket.c:145 #3 0x5555596adebb in tcp_chr_connect_client_task /home/elmarco/src/qq/chardev/char-socket.c:1104 #4 0x555559723d55 in qio_task_thread_worker /home/elmarco/src/qq/io/task.c:123 #5 0x5555598a6731 in qemu_thread_start /home/elmarco/src/qq/util/qemu-thread-posix.c:519 #6 0x7ffff40d4431 in start_thread (/lib64/libpthread.so.0+0x9431) #7 0x7ffff40029d2 in __clone (/lib64/libc.so.6+0x1019d2) Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20200420112012.567284-1-marcandre.lureau@redhat.com> --- chardev/char-socket.c | 3 ++- tests/test-char.c | 54 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 320aa7c642..ef62dbf3d7 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1129,7 +1129,8 @@ static void tcp_chr_connect_client_async(Chardev *chr) */ s->connect_task = qio_task_new(OBJECT(sioc), qemu_chr_socket_connected, - chr, NULL); + object_ref(OBJECT(chr)), + (GDestroyNotify)object_unref); qio_task_run_in_thread(s->connect_task, tcp_chr_connect_client_task, s->addr, diff --git a/tests/test-char.c b/tests/test-char.c index 73ba1cf601..9d8746414d 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -904,6 +904,52 @@ typedef struct { char_socket_cb event_cb; } CharSocketClientTestConfig; +static void char_socket_client_dupid_test(gconstpointer opaque) +{ + const CharSocketClientTestConfig *config = opaque; + QIOChannelSocket *ioc; + char *optstr; + Chardev *chr1, *chr2; + SocketAddress *addr; + QemuOpts *opts; + Error *local_err = NULL; + + /* + * Setup a listener socket and determine get its address + * so we know the TCP port for the client later + */ + ioc = qio_channel_socket_new(); + g_assert_nonnull(ioc); + qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); + addr = qio_channel_socket_get_local_address(ioc, &error_abort); + g_assert_nonnull(addr); + + /* + * Populate the chardev address based on what the server + * is actually listening on + */ + optstr = char_socket_addr_to_opt_str(addr, + config->fd_pass, + config->reconnect, + false); + + opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), + optstr, true); + g_assert_nonnull(opts); + chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); + g_assert_nonnull(chr1); + + chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); + g_assert_null(chr2); + error_free_or_abort(&local_err); + + object_unref(OBJECT(ioc)); + qemu_opts_del(opts); + object_unparent(OBJECT(chr1)); + qapi_free_SocketAddress(addr); + g_free(optstr); +} + static void char_socket_client_test(gconstpointer opaque) { const CharSocketClientTestConfig *config = opaque; @@ -1456,7 +1502,7 @@ int main(int argc, char **argv) #define SOCKET_CLIENT_TEST(name, addr) \ static CharSocketClientTestConfig client1 ## name = \ - { addr, NULL, false, false, char_socket_event}; \ + { addr, NULL, false, false, char_socket_event }; \ static CharSocketClientTestConfig client2 ## name = \ { addr, NULL, true, false, char_socket_event }; \ static CharSocketClientTestConfig client3 ## name = \ @@ -1470,6 +1516,8 @@ int main(int argc, char **argv) static CharSocketClientTestConfig client7 ## name = \ { addr, ",reconnect=1", true, false, \ char_socket_event_with_error }; \ + static CharSocketClientTestConfig client8 ## name = \ + { addr, ",reconnect=1", false, false, char_socket_event }; \ g_test_add_data_func("/char/socket/client/mainloop/" # name, \ &client1 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ @@ -1483,7 +1531,9 @@ int main(int argc, char **argv) g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ &client6 ##name, char_socket_client_test); \ g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ - &client7 ##name, char_socket_client_test) + &client7 ##name, char_socket_client_test); \ + g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ + &client8 ##name, char_socket_client_dupid_test) if (has_ipv4) { SOCKET_SERVER_TEST(tcp, &tcpaddr); From 833ef7ec5677ac3f6627f44fbd599cfb16581220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:06 +0200 Subject: [PATCH 4/8] monitor/misc: Remove unused "chardev/char-mux.h" include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit monitor/misc.c never required "chardev/char-mux.h", remove it. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-2-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- monitor/misc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/monitor/misc.c b/monitor/misc.c index 89bb970b00..e847b58a8c 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -33,7 +33,6 @@ #include "exec/gdbstub.h" #include "net/net.h" #include "net/slirp.h" -#include "chardev/char-mux.h" #include "ui/qemu-spice.h" #include "qemu/config-file.h" #include "qemu/ctype.h" From 35b49e93fda0498fe1a8663a6ad3db11756d7e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:07 +0200 Subject: [PATCH 5/8] tests/test-char: Remove unused "chardev/char-mux.h" include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test never required "chardev/char-mux.h", remove it. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-3-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- tests/test-char.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test-char.c b/tests/test-char.c index 9d8746414d..614bdac2df 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -6,7 +6,6 @@ #include "qemu/option.h" #include "qemu/sockets.h" #include "chardev/char-fe.h" -#include "chardev/char-mux.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qapi-commands-char.h" From c383efd50a12991a23921e37541c6e5f1bfec1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:08 +0200 Subject: [PATCH 6/8] chardev: Restrict msmouse / wctablet / testdev to system emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The msmouse / wctablet / testdev character devices are only used by system emulation. Remove them from user mode and tools. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-4-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index 3a58c9d329..62ec0a3323 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -17,7 +17,7 @@ chardev-obj-y += char-udp.o chardev-obj-$(CONFIG_WIN32) += char-win.o chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o -common-obj-y += msmouse.o wctablet.o testdev.o +common-obj-$(CONFIG_SOFTMMU) += msmouse.o wctablet.o testdev.o ifeq ($(CONFIG_BRLAPI),y) common-obj-m += baum.o From ffa0f7eb57f3fbb4947e5bf12040108481ea46c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:09 +0200 Subject: [PATCH 7/8] chardev: Reduce "char-mux.h" scope, rename it "chardev-internal.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No file out of chardev/ requires access to this header, restrict its scope. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-5-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/char-fe.c | 2 +- chardev/char-mux.c | 2 +- chardev/char.c | 2 +- include/chardev/char-mux.h => chardev/chardev-internal.h | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) rename include/chardev/char-mux.h => chardev/chardev-internal.h (96%) diff --git a/chardev/char-fe.c b/chardev/char-fe.c index f3530a90e6..474715c5a9 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -29,7 +29,7 @@ #include "chardev/char-fe.h" #include "chardev/char-io.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len) { diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 46c44af67c..6f980bb836 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -29,7 +29,7 @@ #include "chardev/char.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" /* MUX driver for serial I/O splitting */ diff --git a/chardev/char.c b/chardev/char.c index a0626d04d5..807be52300 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -40,7 +40,7 @@ #include "qemu/id.h" #include "qemu/coroutine.h" -#include "chardev/char-mux.h" +#include "chardev-internal.h" /***********************************************************/ /* character device */ diff --git a/include/chardev/char-mux.h b/chardev/chardev-internal.h similarity index 96% rename from include/chardev/char-mux.h rename to chardev/chardev-internal.h index 417fe32eed..e0264ac349 100644 --- a/include/chardev/char-mux.h +++ b/chardev/chardev-internal.h @@ -1,5 +1,5 @@ /* - * QEMU System Emulator + * QEMU Character device internals * * Copyright (c) 2003-2008 Fabrice Bellard * @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef CHAR_MUX_H -#define CHAR_MUX_H +#ifndef CHARDEV_INTERNAL_H +#define CHARDEV_INTERNAL_H #include "chardev/char.h" #include "chardev/char-fe.h" @@ -30,6 +30,7 @@ #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) + typedef struct MuxChardev { Chardev parent; CharBackend *backends[MAX_MUX]; From 30827bad3852fd85d86995e7ccab429679442889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 23 Apr 2020 22:21:10 +0200 Subject: [PATCH 8/8] chardev: Extract system emulation specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out code only used during system emulation, to reduce code pulled in user emulation and tools. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200423202112.644-6-philmd@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Marc-André Lureau --- chardev/Makefile.objs | 1 + chardev/char.c | 35 +------------------ chardev/chardev-internal.h | 3 ++ chardev/chardev-sysemu.c | 69 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 chardev/chardev-sysemu.c diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index 62ec0a3323..3783dadc4c 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -1,4 +1,5 @@ chardev-obj-y += char.o +chardev-obj-$(CONFIG_SOFTMMU) += chardev-sysemu.o chardev-obj-$(CONFIG_WIN32) += char-console.o chardev-obj-$(CONFIG_POSIX) += char-fd.o chardev-obj-y += char-fe.o diff --git a/chardev/char.c b/chardev/char.c index 807be52300..77e7ec814f 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -45,7 +45,7 @@ /***********************************************************/ /* character device */ -static Object *get_chardevs_root(void) +Object *get_chardevs_root(void) { return container_get(object_get_root(), "/chardevs"); } @@ -305,33 +305,6 @@ static const TypeInfo char_type_info = { .class_init = char_class_init, }; -static int chardev_machine_done_notify_one(Object *child, void *opaque) -{ - Chardev *chr = (Chardev *)child; - ChardevClass *class = CHARDEV_GET_CLASS(chr); - - if (class->chr_machine_done) { - return class->chr_machine_done(chr); - } - - return 0; -} - -static void chardev_machine_done_hook(Notifier *notifier, void *unused) -{ - int ret = object_child_foreach(get_chardevs_root(), - chardev_machine_done_notify_one, NULL); - - if (ret) { - error_report("Failed to call chardev machine_done hooks"); - exit(1); - } -} - -static Notifier chardev_machine_done_notify = { - .notify = chardev_machine_done_hook, -}; - static bool qemu_chr_is_busy(Chardev *s) { if (CHARDEV_IS_MUX(s)) { @@ -1198,12 +1171,6 @@ void qemu_chr_cleanup(void) static void register_types(void) { type_register_static(&char_type_info); - - /* this must be done after machine init, since we register FEs with muxes - * as part of realize functions like serial_isa_realizefn when -nographic - * is specified - */ - qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); } type_init(register_types); diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h index e0264ac349..f4d0429763 100644 --- a/chardev/chardev-internal.h +++ b/chardev/chardev-internal.h @@ -26,6 +26,7 @@ #include "chardev/char.h" #include "chardev/char-fe.h" +#include "qom/object.h" #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ @@ -59,4 +60,6 @@ typedef struct MuxChardev { void mux_set_focus(Chardev *chr, int focus); void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event); +Object *get_chardevs_root(void); + #endif /* CHAR_MUX_H */ diff --git a/chardev/chardev-sysemu.c b/chardev/chardev-sysemu.c new file mode 100644 index 0000000000..eecdc615ee --- /dev/null +++ b/chardev/chardev-sysemu.c @@ -0,0 +1,69 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "chardev/char.h" +#include "qemu/error-report.h" +#include "chardev-internal.h" + +static int chardev_machine_done_notify_one(Object *child, void *opaque) +{ + Chardev *chr = (Chardev *)child; + ChardevClass *class = CHARDEV_GET_CLASS(chr); + + if (class->chr_machine_done) { + return class->chr_machine_done(chr); + } + + return 0; +} + +static void chardev_machine_done_hook(Notifier *notifier, void *unused) +{ + int ret = object_child_foreach(get_chardevs_root(), + chardev_machine_done_notify_one, NULL); + + if (ret) { + error_report("Failed to call chardev machine_done hooks"); + exit(1); + } +} + + +static Notifier chardev_machine_done_notify = { + .notify = chardev_machine_done_hook, +}; + +static void register_types(void) +{ + /* + * This must be done after machine init, since we register FEs with muxes + * as part of realize functions like serial_isa_realizefn when -nographic + * is specified. + */ + qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); +} + +type_init(register_types);