static void remove_fd_in_watch(CharDriverState *chr);
static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
-static void mux_set_focus(MuxDriver *d, int focus);
+static void mux_set_focus(CharDriverState *chr, int focus);
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
static CharDriverState *qemu_chr_open_null(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
return NULL;
}
chr->chr_write = null_chr_write;
- chr->explicit_be_open = true;
+ *be_opened = false;
return chr;
}
case 'c':
assert(d->mux_cnt > 0); /* handler registered with first fe */
/* Switch to the next registered device */
- mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
+ mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
break;
case 't':
d->timestamps = !d->timestamps;
}
}
+static bool muxes_realized;
+
static void mux_chr_event(void *opaque, int event)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
int i;
+ if (!muxes_realized) {
+ return;
+ }
+
/* Send the event to all registered listeners */
for (i = 0; i < d->mux_cnt; i++)
mux_chr_send_event(d, i, event);
}
-static bool muxes_realized;
-
/**
* Called after processing of default and command-line-specified
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
g_free(d);
}
-static int mux_chr_new_fe(CharDriverState *chr, CharBackend *be, Error **errp)
-{
- MuxDriver *d = chr->opaque;
-
- if (d->mux_cnt >= MAX_MUX) {
- fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
- return -1;
- }
-
- d->backends[d->mux_cnt] = be;
-
- return d->mux_cnt++;
-}
-
static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
{
MuxDriver *d = chr->opaque;
context, true);
}
-static void mux_set_focus(MuxDriver *d, int focus)
+static void mux_set_focus(CharDriverState *chr, int focus)
{
+ MuxDriver *d = chr->opaque;
+
assert(focus >= 0);
assert(focus < d->mux_cnt);
}
d->focus = focus;
+ chr->be = d->backends[focus];
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
}
static CharDriverState *qemu_chr_open_mux(const char *id,
ChardevBackend *backend,
- ChardevReturn *ret, Error **errp)
+ ChardevReturn *ret,
+ bool *be_opened,
+ Error **errp)
{
ChardevMux *mux = backend->u.mux.data;
CharDriverState *chr, *drv;
/* only default to opened state if we've realized the initial
* set of muxes
*/
- chr->explicit_be_open = muxes_realized ? 0 : 1;
+ *be_opened = muxes_realized;
chr->is_mux = 1;
if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
qemu_chr_free(chr);
int tag = 0;
if (s->is_mux) {
- tag = mux_chr_new_fe(s, b, errp);
- if (tag < 0) {
- return false;
+ MuxDriver *d = s->opaque;
+
+ if (d->mux_cnt >= MAX_MUX) {
+ goto unavailable;
}
+
+ d->backends[d->mux_cnt] = b;
+ tag = d->mux_cnt++;
+ } else if (s->be) {
+ goto unavailable;
} else {
s->be = b;
}
+ b->fe_open = false;
b->tag = tag;
b->chr = s;
-
return true;
+
+unavailable:
+ error_setg(errp, QERR_DEVICE_IN_USE, s->label);
+ return false;
}
static bool qemu_chr_is_busy(CharDriverState *s)
if (b->chr) {
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
- b->chr->avail_connections++;
- b->chr->be = NULL;
+ if (b->chr->be == b) {
+ b->chr->be = NULL;
+ }
if (b->chr->is_mux) {
MuxDriver *d = b->chr->opaque;
d->backends[b->tag] = NULL;
}
if (b->chr->is_mux) {
- mux_set_focus(b->chr->opaque, b->tag);
+ mux_set_focus(b->chr, b->tag);
}
}
};
/* Can only be used for read */
-static guint io_add_watch_poll(QIOChannel *ioc,
+static guint io_add_watch_poll(CharDriverState *chr,
+ QIOChannel *ioc,
IOCanReadHandler *fd_can_read,
QIOChannelFunc fd_read,
gpointer user_data,
{
IOWatchPoll *iwp;
int tag;
+ char *name;
iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
sizeof(IOWatchPoll));
iwp->src = NULL;
iwp->context = context;
+ name = g_strdup_printf("chardev-iowatch-%s", chr->label);
+ g_source_set_name((GSource *)iwp, name);
+ g_free(name);
+
tag = g_source_attach(&iwp->parent, context);
g_source_unref(&iwp->parent);
return tag;
remove_fd_in_watch(chr);
if (s->ioc_in) {
- chr->fd_in_tag = io_add_watch_poll(s->ioc_in,
+ chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
fd_chr_read_poll,
fd_chr_read, chr,
context);
{
CharDriverState *chr;
FDCharDriver *s;
+ char *name;
chr = qemu_chr_alloc(backend, errp);
if (!chr) {
}
s = g_new0(FDCharDriver, 1);
s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
+ name = g_strdup_printf("chardev-file-in-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
+ g_free(name);
s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
+ name = g_strdup_printf("chardev-file-out-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
+ g_free(name);
qemu_set_nonblock(fd_out);
s->chr = chr;
chr->opaque = s;
static CharDriverState *qemu_chr_open_pipe(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevHostdev *opts = backend->u.pipe.data;
static CharDriverState *qemu_chr_open_stdio(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevStdio *opts = backend->u.stdio.data;
static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
{
PtyCharDriver *s = chr->opaque;
+ char *name;
if (s->timer_tag) {
g_source_remove(s->timer_tag);
}
if (ms == 1000) {
+ name = g_strdup_printf("pty-timer-secs-%s", chr->label);
s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
} else {
+ name = g_strdup_printf("pty-timer-ms-%s", chr->label);
s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
}
+ g_source_set_name_by_id(s->timer_tag, name);
+ g_free(name);
}
/* Called with chr_write_lock held. */
s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
}
if (!chr->fd_in_tag) {
- chr->fd_in_tag = io_add_watch_poll(s->ioc,
+ chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
pty_chr_read_poll,
pty_chr_read,
chr, NULL);
static CharDriverState *qemu_chr_open_pty(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
int master_fd, slave_fd;
char pty_name[PATH_MAX];
ChardevCommon *common = backend->u.pty.data;
+ char *name;
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
if (master_fd < 0) {
chr->chr_update_read_handler = pty_chr_update_read_handler;
chr->chr_free = pty_chr_free;
chr->chr_add_watch = pty_chr_add_watch;
- chr->explicit_be_open = true;
+ *be_opened = false;
s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
+ name = g_strdup_printf("chardev-pty-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
+ g_free(name);
s->timer_tag = 0;
return chr;
static CharDriverState *qemu_chr_open_tty_fd(int fd,
ChardevCommon *backend,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
static CharDriverState *qemu_chr_open_pp_fd(int fd,
ChardevCommon *backend,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
static CharDriverState *qemu_chr_open_pp_fd(int fd,
ChardevCommon *backend,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
chr->opaque = (void *)(intptr_t)fd;
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
- chr->explicit_be_open = true;
+ *be_opened = false;
return chr;
}
#endif
static CharDriverState *qemu_chr_open_pipe(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevHostdev *opts = backend->u.pipe.data;
static CharDriverState *qemu_chr_open_win_con(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevCommon *common = backend->u.console.data;
static CharDriverState *qemu_chr_open_stdio(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
remove_fd_in_watch(chr);
if (s->ioc) {
- chr->fd_in_tag = io_add_watch_poll(s->ioc,
+ chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
udp_chr_read_poll,
udp_chr_read, chr,
context);
static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
ChardevCommon *backend,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr = NULL;
chr->chr_update_read_handler = udp_chr_update_read_handler;
chr->chr_free = udp_chr_free;
/* be isn't opened until we get a connection */
- chr->explicit_be_open = true;
+ *be_opened = false;
return chr;
}
static void qemu_chr_socket_restart_timer(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
+ char *name;
assert(s->connected == 0);
s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
socket_reconnect_timeout, chr);
+ name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
+ g_source_set_name_by_id(s->reconnect_timer, name);
+ g_free(name);
}
static void check_report_connect_error(CharDriverState *chr,
s->connected = 1;
if (s->ioc) {
- chr->fd_in_tag = io_add_watch_poll(s->ioc,
+ chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll,
tcp_chr_read,
chr, NULL);
remove_fd_in_watch(chr);
if (s->ioc) {
- chr->fd_in_tag = io_add_watch_poll(s->ioc,
+ chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll,
tcp_chr_read, chr,
context);
}
-static void tcp_chr_tls_handshake(Object *source,
- Error *err,
+static void tcp_chr_tls_handshake(QIOTask *task,
gpointer user_data)
{
CharDriverState *chr = user_data;
TCPCharDriver *s = chr->opaque;
- if (err) {
+ if (qio_task_propagate_error(task, NULL)) {
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
TCPCharDriver *s = chr->opaque;
QIOChannelTLS *tioc;
Error *err = NULL;
+ gchar *name;
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
tcp_chr_disconnect(chr);
return;
}
+ name = g_strdup_printf("chardev-tls-%s-%s",
+ s->is_listen ? "server" : "client",
+ chr->label);
+ qio_channel_set_name(QIO_CHANNEL(tioc), name);
+ g_free(name);
object_unref(OBJECT(s->ioc));
s->ioc = QIO_CHANNEL(tioc);
}
+static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
+ QIOChannelSocket *sioc)
+{
+ TCPCharDriver *s = chr->opaque;
+ char *name;
+ name = g_strdup_printf("chardev-tcp-%s-%s",
+ s->is_listen ? "server" : "client",
+ chr->label);
+ qio_channel_set_name(QIO_CHANNEL(sioc), name);
+ g_free(name);
+
+}
+
static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
{
TCPCharDriver *s = chr->opaque;
if (!sioc) {
return -1;
}
+ tcp_chr_set_client_ioc_name(chr, sioc);
ret = tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
return ret;
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
} else {
sioc = qio_channel_socket_new();
+ tcp_chr_set_client_ioc_name(chr, sioc);
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
object_unref(OBJECT(sioc));
return -1;
}
-static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
+static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
{
- QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
+ Error *err = NULL;
- if (err) {
+ if (qio_task_propagate_error(task, &err)) {
check_report_connect_error(chr, err);
- object_unref(src);
- return;
+ error_free(err);
+ goto cleanup;
}
s->connect_err_reported = false;
tcp_chr_new_client(chr, sioc);
+
+ cleanup:
object_unref(OBJECT(sioc));
}
static CharDriverState *qemu_chr_open_ringbuf(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevRingbuf *opts = backend->u.ringbuf.data;
typedef struct CharDriver {
const char *name;
ChardevBackendKind kind;
- void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
- CharDriverState *(*create)(const char *id, ChardevBackend *backend,
- ChardevReturn *ret, Error **errp);
+ CharDriverParse *parse;
+ CharDriverCreate *create;
} CharDriver;
static GSList *backends;
void register_char_driver(const char *name, ChardevBackendKind kind,
- void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp),
- CharDriverState *(*create)(const char *id, ChardevBackend *backend,
- ChardevReturn *ret, Error **errp))
+ CharDriverParse *parse, CharDriverCreate *create)
{
CharDriver *s;
return;
}
- if (chr->fe_open == fe_open) {
+ if (be->fe_open == fe_open) {
return;
}
- chr->fe_open = fe_open;
+ be->fe_open = fe_open;
if (chr->chr_set_fe_open) {
chr->chr_set_fe_open(chr, fe_open);
}
}
-void qemu_chr_fe_event(CharBackend *be, int event)
-{
- CharDriverState *chr = be->chr;
-
- if (chr && chr->chr_fe_event) {
- chr->chr_fe_event(chr, event);
- }
-}
-
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
GIOFunc func, void *user_data)
{
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->fe_open;
+ info->value->frontend_open = chr->be && chr->be->fe_open;
info->next = chr_list;
chr_list = info;
static CharDriverState *qmp_chardev_open_file(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevFile *file = backend->u.file.data;
static CharDriverState *qmp_chardev_open_serial(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevHostdev *serial = backend->u.serial.data;
static CharDriverState *qmp_chardev_open_file(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevFile *file = backend->u.file.data;
static CharDriverState *qmp_chardev_open_serial(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevHostdev *serial = backend->u.serial.data;
return NULL;
}
qemu_set_nonblock(fd);
- return qemu_chr_open_tty_fd(fd, common, errp);
+ return qemu_chr_open_tty_fd(fd, common, be_opened, errp);
}
#endif
static CharDriverState *qmp_chardev_open_parallel(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevHostdev *parallel = backend->u.parallel.data;
if (fd < 0) {
return NULL;
}
- return qemu_chr_open_pp_fd(fd, common, errp);
+ return qemu_chr_open_pp_fd(fd, common, be_opened, errp);
}
#endif
}
sioc = qio_channel_socket_new();
+ tcp_chr_set_client_ioc_name(chr, sioc);
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL);
static CharDriverState *qmp_chardev_open_socket(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
CharDriverState *chr;
chr->chr_add_watch = tcp_chr_add_watch;
chr->chr_update_read_handler = tcp_chr_update_read_handler;
/* be isn't opened until we get a connection */
- chr->explicit_be_open = true;
+ *be_opened = false;
chr->filename = SocketAddress_to_str("disconnected:",
addr, is_listen, is_telnet);
if (s->reconnect_time) {
sioc = qio_channel_socket_new();
+ tcp_chr_set_client_ioc_name(chr, sioc);
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL);
} else {
if (s->is_listen) {
+ char *name;
sioc = qio_channel_socket_new();
+
+ name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(sioc), name);
+ g_free(name);
+
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
goto error;
}
static CharDriverState *qmp_chardev_open_udp(const char *id,
ChardevBackend *backend,
ChardevReturn *ret,
+ bool *be_opened,
Error **errp)
{
ChardevUdp *udp = backend->u.udp.data;
ChardevCommon *common = qapi_ChardevUdp_base(udp);
QIOChannelSocket *sioc = qio_channel_socket_new();
+ char *name;
+ CharDriverState *chr;
if (qio_channel_socket_dgram_sync(sioc,
udp->local, udp->remote,
object_unref(OBJECT(sioc));
return NULL;
}
- return qemu_chr_open_udp(sioc, common, errp);
+ chr = qemu_chr_open_udp(sioc, common, be_opened, errp);
+
+ name = g_strdup_printf("chardev-udp-%s", chr->label);
+ qio_channel_set_name(QIO_CHANNEL(sioc), name);
+ g_free(name);
+
+ return chr;
}
Error *local_err = NULL;
GSList *i;
CharDriver *cd;
+ bool be_opened = true;
chr = qemu_chr_find(id);
if (chr) {
error_setg(errp, "Chardev '%s' already exists", id);
- g_free(ret);
- return NULL;
+ goto out_error;
}
for (i = backends; i; i = i->next) {
cd = i->data;
if (cd->kind == backend->type) {
- chr = cd->create(id, backend, ret, &local_err);
+ chr = cd->create(id, backend, ret, &be_opened, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out_error;
}
chr->label = g_strdup(id);
- chr->avail_connections =
- (backend->type == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
if (!chr->filename) {
chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
}
- if (!chr->explicit_be_open) {
+ if (be_opened) {
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
QTAILQ_INSERT_TAIL(&chardevs, chr, next);