summaryrefslogtreecommitdiffstats
path: root/chardev
diff options
context:
space:
mode:
Diffstat (limited to 'chardev')
-rw-r--r--chardev/char-fe.c13
-rw-r--r--chardev/char-io.c48
-rw-r--r--chardev/char-pty.c8
-rw-r--r--chardev/char-socket.c94
-rw-r--r--chardev/char.c39
5 files changed, 86 insertions, 116 deletions
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index b1f228e8b5..a8931f7afd 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -56,7 +56,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
{
Chardev *s = be->chr;
- int offset = 0, counter = 10;
+ int offset = 0;
int res;
if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
@@ -88,10 +88,6 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
}
offset += res;
-
- if (!counter--) {
- break;
- }
}
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
@@ -239,7 +235,12 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
d->backends[b->tag] = NULL;
}
if (del) {
- object_unparent(OBJECT(b->chr));
+ Object *obj = OBJECT(b->chr);
+ if (obj->parent) {
+ object_unparent(obj);
+ } else {
+ object_unref(obj);
+ }
}
b->chr = NULL;
}
diff --git a/chardev/char-io.c b/chardev/char-io.c
index f81052481a..8ced184160 100644
--- a/chardev/char-io.c
+++ b/chardev/char-io.c
@@ -33,7 +33,6 @@ typedef struct IOWatchPoll {
IOCanReadHandler *fd_can_read;
GSourceFunc fd_read;
void *opaque;
- GMainContext *context;
} IOWatchPoll;
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
@@ -55,47 +54,24 @@ static gboolean io_watch_poll_prepare(GSource *source,
iwp->src = qio_channel_create_watch(
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
- g_source_attach(iwp->src, iwp->context);
- } else {
- g_source_destroy(iwp->src);
+ g_source_add_child_source(source, iwp->src);
g_source_unref(iwp->src);
+ } else {
+ g_source_remove_child_source(source, iwp->src);
iwp->src = NULL;
}
return FALSE;
}
-static gboolean io_watch_poll_check(GSource *source)
-{
- return FALSE;
-}
-
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
- abort();
-}
-
-static void io_watch_poll_finalize(GSource *source)
-{
- /* Due to a glib bug, removing the last reference to a source
- * inside a finalize callback causes recursive locking (and a
- * deadlock). This is not a problem inside other callbacks,
- * including dispatch callbacks, so we call io_remove_watch_poll
- * to remove this source. At this point, iwp->src must
- * be NULL, or we would leak it.
- *
- * This would be solved much more elegantly by child sources,
- * but we support older glib versions that do not have them.
- */
- IOWatchPoll *iwp = io_watch_poll_from_source(source);
- assert(iwp->src == NULL);
+ return G_SOURCE_CONTINUE;
}
static GSourceFuncs io_watch_poll_funcs = {
.prepare = io_watch_poll_prepare,
- .check = io_watch_poll_check,
.dispatch = io_watch_poll_dispatch,
- .finalize = io_watch_poll_finalize,
};
GSource *io_add_watch_poll(Chardev *chr,
@@ -115,7 +91,6 @@ GSource *io_add_watch_poll(Chardev *chr,
iwp->ioc = ioc;
iwp->fd_read = (GSourceFunc) fd_read;
iwp->src = NULL;
- iwp->context = context;
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
g_source_set_name((GSource *)iwp, name);
@@ -126,23 +101,10 @@ GSource *io_add_watch_poll(Chardev *chr,
return (GSource *)iwp;
}
-static void io_remove_watch_poll(GSource *source)
-{
- IOWatchPoll *iwp;
-
- iwp = io_watch_poll_from_source(source);
- if (iwp->src) {
- g_source_destroy(iwp->src);
- g_source_unref(iwp->src);
- iwp->src = NULL;
- }
- g_source_destroy(&iwp->parent);
-}
-
void remove_fd_in_watch(Chardev *chr)
{
if (chr->gsource) {
- io_remove_watch_poll(chr->gsource);
+ g_source_destroy(chr->gsource);
chr->gsource = NULL;
}
}
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index 68fd4e20c3..f681d637c1 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -31,10 +31,6 @@
#include "chardev/char-io.h"
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
- || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
- || defined(__GLIBC__)
-
typedef struct {
Chardev parent;
QIOChannel *ioc;
@@ -263,7 +259,7 @@ static void char_pty_open(Chardev *chr,
qemu_set_nonblock(master_fd);
chr->filename = g_strdup_printf("pty:%s", pty_name);
- error_report("char device redirected to %s (label %s)",
+ error_printf("char device redirected to %s (label %s)\n",
pty_name, chr->label);
s = PTY_CHARDEV(chr);
@@ -299,5 +295,3 @@ static void register_types(void)
}
type_init(register_types);
-
-#endif
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index efbad6ee7c..a75b46d9fe 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -32,7 +32,6 @@
#include "qapi/error.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
-#include "sysemu/sysemu.h"
#include "chardev/char-io.h"
@@ -354,6 +353,15 @@ static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
return qio_channel_create_watch(s->ioc, cond);
}
+static void remove_hup_source(SocketChardev *s)
+{
+ if (s->hup_source != NULL) {
+ g_source_destroy(s->hup_source);
+ g_source_unref(s->hup_source);
+ s->hup_source = NULL;
+ }
+}
+
static void tcp_chr_free_connection(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
@@ -368,11 +376,7 @@ static void tcp_chr_free_connection(Chardev *chr)
s->read_msgfds_num = 0;
}
- if (s->hup_source != NULL) {
- g_source_destroy(s->hup_source);
- g_source_unref(s->hup_source);
- s->hup_source = NULL;
- }
+ remove_hup_source(s);
tcp_set_msgfds(chr, NULL, 0);
remove_fd_in_watch(chr);
@@ -419,8 +423,12 @@ 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);
+ if (s->addr) {
+ chr->filename = SocketAddress_to_str("disconnected:", s->addr,
+ s->is_listen, s->is_telnet);
+ } else {
+ chr->filename = g_strdup("disconnected:socket");
+ }
}
/* NB may be called even if tcp_chr_connect has not been
@@ -541,6 +549,27 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
}
}
+static void update_ioc_handlers(SocketChardev *s)
+{
+ Chardev *chr = CHARDEV(s);
+
+ if (!s->connected) {
+ return;
+ }
+
+ remove_fd_in_watch(chr);
+ chr->gsource = io_add_watch_poll(chr, s->ioc,
+ tcp_chr_read_poll,
+ tcp_chr_read, chr,
+ chr->gcontext);
+
+ remove_hup_source(s);
+ s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
+ g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
+ chr, NULL);
+ g_source_attach(s->hup_source, chr->gcontext);
+}
+
static void tcp_chr_connect(void *opaque)
{
Chardev *chr = CHARDEV(opaque);
@@ -553,16 +582,7 @@ static void tcp_chr_connect(void *opaque)
s->is_listen, s->is_telnet);
s->connected = 1;
- chr->gsource = io_add_watch_poll(chr, s->ioc,
- tcp_chr_read_poll,
- tcp_chr_read,
- chr, chr->gcontext);
-
- s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
- g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
- chr, NULL);
- g_source_attach(s->hup_source, chr->gcontext);
-
+ update_ioc_handlers(s);
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
@@ -593,17 +613,7 @@ static void tcp_chr_update_read_handler(Chardev *chr)
tcp_chr_telnet_init(CHARDEV(s));
}
- if (!s->connected) {
- return;
- }
-
- remove_fd_in_watch(chr);
- if (s->ioc) {
- chr->gsource = io_add_watch_poll(chr, s->ioc,
- tcp_chr_read_poll,
- tcp_chr_read, chr,
- chr->gcontext);
- }
+ update_ioc_handlers(s);
}
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
@@ -724,11 +734,6 @@ static void tcp_chr_tls_init(Chardev *chr)
Error *err = NULL;
gchar *name;
- if (!machine_init_done) {
- /* This will be postponed to machine_done notifier */
- return;
- }
-
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
@@ -1011,8 +1016,9 @@ static void qmp_chardev_open_socket(Chardev *chr,
s->reconnect_time = reconnect;
}
- /* If reconnect_time is set, will do that in chr_machine_done. */
- if (!s->reconnect_time) {
+ if (s->reconnect_time) {
+ tcp_chr_connect_async(chr);
+ } else {
if (s->is_listen) {
char *name;
s->listener = qio_net_listener_new();
@@ -1161,21 +1167,6 @@ char_socket_get_connected(Object *obj, Error **errp)
return s->connected;
}
-static int tcp_chr_machine_done_hook(Chardev *chr)
-{
- SocketChardev *s = SOCKET_CHARDEV(chr);
-
- if (s->reconnect_time) {
- tcp_chr_connect_async(chr);
- }
-
- if (s->ioc && s->tls_creds) {
- tcp_chr_tls_init(chr);
- }
-
- return 0;
-}
-
static void char_socket_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1191,7 +1182,6 @@ 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;
- cc->chr_machine_done = tcp_chr_machine_done_hook;
object_class_property_add(oc, "addr", "SocketAddress",
char_socket_get_addr, NULL,
diff --git a/chardev/char.c b/chardev/char.c
index 76d866e6fe..7f07a1bfbd 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -329,7 +329,8 @@ int qemu_chr_wait_connected(Chardev *chr, Error **errp)
return 0;
}
-QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
+QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
+ bool permit_mux_mon)
{
char host[65], port[33], width[8], height[8];
int pos;
@@ -344,6 +345,10 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
}
if (strstart(filename, "mon:", &p)) {
+ if (!permit_mux_mon) {
+ error_report("mon: isn't supported in this context");
+ return NULL;
+ }
filename = p;
qemu_opt_set(opts, "mux", "on", &error_abort);
if (strcmp(filename, "stdio") == 0) {
@@ -629,7 +634,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp)
chardev_name_foreach(help_string_append, str);
- error_report("Available chardev backend types: %s", str->str);
+ error_printf("Available chardev backend types: %s\n", str->str);
g_string_free(str, true);
return NULL;
}
@@ -683,7 +688,8 @@ out:
return chr;
}
-Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
+Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
+ bool permit_mux_mon)
{
const char *p;
Chardev *chr;
@@ -694,25 +700,32 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
return qemu_chr_find(p);
}
- opts = qemu_chr_parse_compat(label, filename);
+ opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
if (!opts)
return NULL;
chr = qemu_chr_new_from_opts(opts, &err);
- if (err) {
+ if (!chr) {
error_report_err(err);
+ goto out;
}
- if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
+
+ if (qemu_opt_get_bool(opts, "mux", 0)) {
+ assert(permit_mux_mon);
monitor_init(chr, MONITOR_USE_READLINE);
}
+
+out:
qemu_opts_del(opts);
return chr;
}
-Chardev *qemu_chr_new(const char *label, const char *filename)
+static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
+ const char *filename,
+ bool permit_mux_mon)
{
Chardev *chr;
- chr = qemu_chr_new_noreplay(label, filename);
+ chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon);
if (chr) {
if (replay_mode != REPLAY_MODE_NONE) {
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
@@ -726,6 +739,16 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
return chr;
}
+Chardev *qemu_chr_new(const char *label, const char *filename)
+{
+ return qemu_chr_new_permit_mux_mon(label, filename, false);
+}
+
+Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename)
+{
+ return qemu_chr_new_permit_mux_mon(label, filename, true);
+}
+
static int qmp_query_chardev_foreach(Object *obj, void *data)
{
Chardev *chr = CHARDEV(obj);