diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-05 17:04:07 +0100 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-05 17:07:55 +0100 |
commit | dd1559bb267becbb838de41132ef60771d183e5d (patch) | |
tree | 82524f290a879e29173cefab8c16d4de92f4904e /chardev | |
parent | f03f9f0c10dcfadee5811d43240f0a6af230f1ce (diff) | |
parent | 79c8db5a13c0f4b73f930be0fcff9bbc1237c258 (diff) |
Merge remote-tracking branch 'elmarco/tags/chr-tests-pull-request' into staging
# gpg: Signature made Thu 04 May 2017 12:42:10 PM BST
# gpg: using RSA key 0xDAE8E10975969CE5
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>"
# gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>"
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5
* elmarco/tags/chr-tests-pull-request: (21 commits)
tests: add /char/console test
tests: add /char/udp test
tests: add /char/socket test
tests: add /char/file test
tests: add /char/pipe test
tests: add alias check in /char/ringbuf
char-udp: flush as much buffer as possible
char-socket: add 'connected' property
char-socket: add 'addr' property
char-socket: update local address after listen
char-socket: introduce update_disconnected_filename()
char: useless NULL check
char: remove chardevs list
char: remove qemu_chardev_add
char: use /chardevs container instead of chardevs list
vl: add todo note about root container cleanup
char: add a /chardevs container
container: don't leak container reference
xen: use a better chardev type check
mux: simplfy muxes_realize_done
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'chardev')
-rw-r--r-- | chardev/char-mux.c | 11 | ||||
-rw-r--r-- | chardev/char-mux.h | 2 | ||||
-rw-r--r-- | chardev/char-pty.c | 2 | ||||
-rw-r--r-- | chardev/char-socket.c | 46 | ||||
-rw-r--r-- | chardev/char-udp.c | 26 | ||||
-rw-r--r-- | chardev/char.c | 148 |
6 files changed, 132 insertions, 103 deletions
diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 5547a36a0a..37d42c65c6 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -114,7 +114,7 @@ static void mux_print_help(Chardev *chr) } } -void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) +static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) { CharBackend *be = d->backends[mux_nr]; @@ -222,9 +222,9 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size) bool muxes_realized; -static void mux_chr_event(void *opaque, int event) +void mux_chr_send_all_event(Chardev *chr, int event) { - MuxChardev *d = MUX_CHARDEV(opaque); + MuxChardev *d = MUX_CHARDEV(chr); int i; if (!muxes_realized) { @@ -237,6 +237,11 @@ static void mux_chr_event(void *opaque, int event) } } +static void mux_chr_event(void *opaque, int event) +{ + mux_chr_send_all_event(CHARDEV(opaque), event); +} + static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond) { MuxChardev *d = MUX_CHARDEV(s); diff --git a/chardev/char-mux.h b/chardev/char-mux.h index 9a2fffce91..3f41dfcfd2 100644 --- a/chardev/char-mux.h +++ b/chardev/char-mux.h @@ -58,6 +58,6 @@ typedef struct MuxChardev { void mux_chr_set_handlers(Chardev *chr, GMainContext *context); void mux_set_focus(Chardev *chr, int focus); -void mux_chr_send_event(MuxChardev *d, int mux_nr, int event); +void mux_chr_send_all_event(Chardev *chr, int event); #endif /* CHAR_MUX_H */ diff --git a/chardev/char-pty.c b/chardev/char-pty.c index a6337be8aa..aa9d0cb2c3 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -185,7 +185,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque) PtyChardev *s = PTY_CHARDEV(opaque); s->open_tag = 0; - qemu_chr_be_generic_open(chr); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); return FALSE; } diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 175fb8c3ec..9d5f062c62 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -385,6 +385,15 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr, } } +static void update_disconnected_filename(SocketChardev *s) +{ + Chardev *chr = CHARDEV(s); + + g_free(chr->filename); + chr->filename = SocketAddress_to_str("disconnected:", s->addr, + s->is_listen, s->is_telnet); +} + static void tcp_chr_disconnect(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -399,8 +408,7 @@ static void tcp_chr_disconnect(Chardev *chr) s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } - chr->filename = SocketAddress_to_str("disconnected:", s->addr, - s->is_listen, s->is_telnet); + update_disconnected_filename(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); if (s->reconnect_time) { qemu_chr_socket_restart_timer(chr); @@ -508,7 +516,7 @@ static void tcp_chr_connect(void *opaque) tcp_chr_read, chr, NULL); } - qemu_chr_be_generic_open(chr); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); } static void tcp_chr_update_read_handler(Chardev *chr, @@ -908,8 +916,7 @@ static void qmp_chardev_open_socket(Chardev *chr, /* be isn't opened until we get a connection */ *be_opened = false; - chr->filename = SocketAddress_to_str("disconnected:", - addr, is_listen, is_telnet); + update_disconnected_filename(s); if (is_listen) { if (is_telnet || is_tn3270) { @@ -937,6 +944,11 @@ static void qmp_chardev_open_socket(Chardev *chr, if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { goto error; } + + qapi_free_SocketAddress(s->addr); + s->addr = socket_local_address(sioc->fd, errp); + update_disconnected_filename(s); + s->listen_ioc = sioc; if (is_waitconnect && qemu_chr_wait_connected(chr, errp) < 0) { @@ -1033,6 +1045,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->addr = addr; } +static void +char_socket_get_addr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + SocketChardev *s = SOCKET_CHARDEV(obj); + + visit_type_SocketAddress(v, name, &s->addr, errp); +} + +static bool +char_socket_get_connected(Object *obj, Error **errp) +{ + SocketChardev *s = SOCKET_CHARDEV(obj); + + return s->connected; +} + static void char_socket_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -1048,6 +1077,13 @@ static void char_socket_class_init(ObjectClass *oc, 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; + + object_class_property_add(oc, "addr", "SocketAddress", + char_socket_get_addr, NULL, + NULL, NULL, &error_abort); + + object_class_property_add_bool(oc, "connected", char_socket_get_connected, + NULL, &error_abort); } static const TypeInfo char_socket_type_info = { diff --git a/chardev/char-udp.c b/chardev/char-udp.c index 804bd22efa..1958c36de4 100644 --- a/chardev/char-udp.c +++ b/chardev/char-udp.c @@ -51,6 +51,18 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) s->ioc, (const char *)buf, len, NULL); } +static void udp_chr_flush_buffer(UdpChardev *s) +{ + Chardev *chr = CHARDEV(s); + + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + int n = MIN(s->max_size, s->bufcnt - s->bufptr); + qemu_chr_be_write(chr, &s->buf[s->bufptr], n); + s->bufptr += n; + s->max_size = qemu_chr_be_can_write(chr); + } +} + static int udp_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); @@ -61,11 +73,8 @@ static int udp_chr_read_poll(void *opaque) /* If there were any stray characters in the queue process them * first */ - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_be_can_write(chr); - } + udp_chr_flush_buffer(s); + return s->max_size; } @@ -85,13 +94,8 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) return FALSE; } s->bufcnt = ret; - s->bufptr = 0; - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_be_can_write(chr); - } + udp_chr_flush_buffer(s); return TRUE; } diff --git a/chardev/char.c b/chardev/char.c index 309734f2b7..fadfedb836 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -42,8 +42,10 @@ /***********************************************************/ /* character device */ -static QTAILQ_HEAD(ChardevHead, Chardev) chardevs = - QTAILQ_HEAD_INITIALIZER(chardevs); +static Object *get_chardevs_root(void) +{ + return container_get(object_get_root(), "/chardevs"); +} void qemu_chr_be_event(Chardev *s, int event) { @@ -66,12 +68,6 @@ void qemu_chr_be_event(Chardev *s, int event) be->chr_event(be->opaque, event); } -void qemu_chr_be_generic_open(Chardev *s) -{ - qemu_chr_be_event(s, CHR_EVENT_OPENED); -} - - /* Not reporting errors from writing to logfile, as logs are * defined to be "best effort" only */ static void qemu_chr_fe_write_log(Chardev *s, @@ -453,26 +449,24 @@ static const TypeInfo char_type_info = { * mux will receive CHR_EVENT_OPENED notifications for the BE * immediately. */ -static void muxes_realize_done(Notifier *notifier, void *unused) +static int open_muxes(Object *child, void *opaque) { - Chardev *chr; + if (CHARDEV_IS_MUX(child)) { + /* send OPENED to all already-attached FEs */ + mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED); + /* mark mux as OPENED so any new FEs will immediately receive + * OPENED event + */ + qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED); + } - QTAILQ_FOREACH(chr, &chardevs, next) { - if (CHARDEV_IS_MUX(chr)) { - MuxChardev *d = MUX_CHARDEV(chr); - int i; + return 0; +} - /* send OPENED to all already-attached FEs */ - for (i = 0; i < d->mux_cnt; i++) { - mux_chr_send_event(d, i, CHR_EVENT_OPENED); - } - /* mark mux as OPENED so any new FEs will immediately receive - * OPENED event - */ - qemu_chr_be_generic_open(chr); - } - } +static void muxes_realize_done(Notifier *notifier, void *unused) +{ muxes_realized = true; + object_child_foreach(get_chardevs_root(), open_muxes, NULL); } static Notifier muxes_realize_notify = { @@ -581,7 +575,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b, /* We're connecting to an already opened device, so let's make sure we also get the open event */ if (s->be_open) { - qemu_chr_be_generic_open(s); + qemu_chr_be_event(s, CHR_EVENT_OPENED); } } @@ -774,7 +768,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) const char *logfile = qemu_opt_get(opts, "logfile"); backend->has_logfile = logfile != NULL; - backend->logfile = logfile ? g_strdup(logfile) : NULL; + backend->logfile = g_strdup(logfile); backend->has_logappend = true; backend->logappend = qemu_opt_get_bool(opts, "logappend", false); @@ -809,26 +803,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) return cc; } -static Chardev *qemu_chardev_add(const char *id, const char *typename, - ChardevBackend *backend, Error **errp) -{ - Chardev *chr; - - chr = qemu_chr_find(id); - if (chr) { - error_setg(errp, "Chardev '%s' already exists", id); - return NULL; - } - - chr = qemu_chardev_new(id, typename, backend, errp); - if (!chr) { - return NULL; - } - - QTAILQ_INSERT_TAIL(&chardevs, chr, next); - return chr; -} - static const struct ChardevAlias { const char *typename; const char *alias; @@ -945,9 +919,10 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, backend->u.null.data = ccom; /* Any ChardevCommon member would work */ } - chr = qemu_chardev_add(bid ? bid : id, + chr = qemu_chardev_new(bid ? bid : id, object_class_get_name(OBJECT_CLASS(cc)), backend, errp); + if (chr == NULL) { goto out; } @@ -959,9 +934,9 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, backend->type = CHARDEV_BACKEND_KIND_MUX; backend->u.mux.data = g_new0(ChardevMux, 1); backend->u.mux.data->chardev = g_strdup(bid); - mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp); + mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp); if (mux == NULL) { - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); chr = NULL; goto out; } @@ -1075,27 +1050,29 @@ void qemu_chr_fe_disconnect(CharBackend *be) } } -void qemu_chr_delete(Chardev *chr) +static int qmp_query_chardev_foreach(Object *obj, void *data) { - QTAILQ_REMOVE(&chardevs, chr, next); - object_unref(OBJECT(chr)); + Chardev *chr = CHARDEV(obj); + ChardevInfoList **list = data; + ChardevInfoList *info = g_malloc0(sizeof(*info)); + + info->value = g_malloc0(sizeof(*info->value)); + info->value->label = g_strdup(chr->label); + info->value->filename = g_strdup(chr->filename); + info->value->frontend_open = chr->be && chr->be->fe_open; + + info->next = *list; + *list = info; + + return 0; } ChardevInfoList *qmp_query_chardev(Error **errp) { ChardevInfoList *chr_list = NULL; - Chardev *chr; - QTAILQ_FOREACH(chr, &chardevs, next) { - ChardevInfoList *info = g_malloc0(sizeof(*info)); - info->value = g_malloc0(sizeof(*info->value)); - info->value->label = g_strdup(chr->label); - info->value->filename = g_strdup(chr->filename); - info->value->frontend_open = chr->be && chr->be->fe_open; - - info->next = chr_list; - chr_list = info; - } + object_child_foreach(get_chardevs_root(), + qmp_query_chardev_foreach, &chr_list); return chr_list; } @@ -1123,14 +1100,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp) Chardev *qemu_chr_find(const char *name) { - Chardev *chr; + Object *obj = object_resolve_path_component(get_chardevs_root(), name); - QTAILQ_FOREACH(chr, &chardevs, next) { - if (strcmp(chr->label, name) != 0) - continue; - return chr; - } - return NULL; + return obj ? CHARDEV(obj) : NULL; } QemuOptsList qemu_chardev_opts = { @@ -1243,22 +1215,23 @@ void qemu_chr_set_feature(Chardev *chr, } Chardev *qemu_chardev_new(const char *id, const char *typename, - ChardevBackend *backend, Error **errp) + ChardevBackend *backend, + Error **errp) { + Object *obj; Chardev *chr = NULL; Error *local_err = NULL; bool be_opened = true; assert(g_str_has_prefix(typename, "chardev-")); - chr = CHARDEV(object_new(typename)); + obj = object_new(typename); + chr = CHARDEV(obj); chr->label = g_strdup(id); qemu_char_open(chr, backend, &be_opened, &local_err); if (local_err) { - error_propagate(errp, local_err); - object_unref(OBJECT(chr)); - return NULL; + goto end; } if (!chr->filename) { @@ -1268,6 +1241,21 @@ Chardev *qemu_chardev_new(const char *id, const char *typename, qemu_chr_be_event(chr, CHR_EVENT_OPENED); } + if (id) { + object_property_add_child(get_chardevs_root(), id, obj, &local_err); + if (local_err) { + goto end; + } + object_unref(obj); + } + +end: + if (local_err) { + error_propagate(errp, local_err); + object_unref(obj); + return NULL; + } + return chr; } @@ -1283,7 +1271,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, return NULL; } - chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)), + chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), backend, errp); if (!chr) { return NULL; @@ -1316,16 +1304,12 @@ void qmp_chardev_remove(const char *id, Error **errp) "Chardev '%s' cannot be unplugged in record/replay mode", id); return; } - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); } void qemu_chr_cleanup(void) { - Chardev *chr, *tmp; - - QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) { - qemu_chr_delete(chr); - } + object_unparent(get_chardevs_root()); } static void register_types(void) |