]> git.proxmox.com Git - mirror_qemu.git/blobdiff - qemu-char.c
virtio-balloon: convert VMSTATE_VIRTIO_DEVICE
[mirror_qemu.git] / qemu-char.c
index 8a0ab05a7bd140f1180604782b99890487b4a6a5..768150d1f8027e9f184a72cfcbf4b4cf50feff9d 100644 (file)
@@ -39,6 +39,7 @@
 #include "io/channel-file.h"
 #include "io/channel-tls.h"
 #include "sysemu/replay.h"
+#include "qemu/help_option.h"
 
 #include <zlib.h>
 
@@ -440,17 +441,20 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
     va_list ap;
     va_start(ap, fmt);
     vsnprintf(buf, sizeof(buf), fmt, ap);
-    qemu_chr_fe_write(s, (uint8_t *)buf, strlen(buf));
+    /* XXX this blocks entire thread. Rewrite to use
+     * qemu_chr_fe_write and background I/O callbacks */
+    qemu_chr_fe_write_all(s, (uint8_t *)buf, strlen(buf));
     va_end(ap);
 }
 
 static void remove_fd_in_watch(CharDriverState *chr);
 
-void qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanReadHandler *fd_can_read,
-                           IOReadHandler *fd_read,
-                           IOEventHandler *fd_event,
-                           void *opaque)
+void qemu_chr_add_handlers_full(CharDriverState *s,
+                                IOCanReadHandler *fd_can_read,
+                                IOReadHandler *fd_read,
+                                IOEventHandler *fd_event,
+                                void *opaque,
+                                GMainContext *context)
 {
     int fe_open;
 
@@ -464,8 +468,9 @@ void qemu_chr_add_handlers(CharDriverState *s,
     s->chr_read = fd_read;
     s->chr_event = fd_event;
     s->handler_opaque = opaque;
-    if (fe_open && s->chr_update_read_handler)
-        s->chr_update_read_handler(s);
+    if (fe_open && s->chr_update_read_handler) {
+        s->chr_update_read_handler(s, context);
+    }
 
     if (!s->explicit_fe_open) {
         qemu_chr_fe_set_open(s, fe_open);
@@ -478,6 +483,16 @@ void qemu_chr_add_handlers(CharDriverState *s,
     }
 }
 
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanReadHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque)
+{
+    qemu_chr_add_handlers_full(s, fd_can_read, fd_read,
+                               fd_event, opaque, NULL);
+}
+
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     return len;
@@ -556,7 +571,9 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                          (secs / 60) % 60,
                          secs % 60,
                          (int)(ti % 1000));
-                qemu_chr_fe_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+                /* XXX this blocks entire thread. Rewrite to use
+                 * qemu_chr_fe_write and background I/O callbacks */
+                qemu_chr_fe_write_all(d->drv, (uint8_t *)buf1, strlen(buf1));
                 d->linestart = 0;
             }
             ret += qemu_chr_fe_write(d->drv, buf+i, 1);
@@ -594,13 +611,15 @@ static void mux_print_help(CharDriverState *chr)
                  "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
                  term_escape_char);
     }
-    qemu_chr_fe_write(chr, (uint8_t *)cbuf, strlen(cbuf));
+    /* XXX this blocks entire thread. Rewrite to use
+     * qemu_chr_fe_write and background I/O callbacks */
+    qemu_chr_fe_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
     for (i = 0; mux_help[i] != NULL; i++) {
         for (j=0; mux_help[i][j] != '\0'; j++) {
             if (mux_help[i][j] == '%')
-                qemu_chr_fe_write(chr, (uint8_t *)ebuf, strlen(ebuf));
+                qemu_chr_fe_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
             else
-                qemu_chr_fe_write(chr, (uint8_t *)&mux_help[i][j], 1);
+                qemu_chr_fe_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
         }
     }
 }
@@ -625,7 +644,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
         case 'x':
             {
                  const char *term =  "QEMU: Terminated\n\r";
-                 qemu_chr_fe_write(chr, (uint8_t *)term, strlen(term));
+                 qemu_chr_fe_write_all(chr, (uint8_t *)term, strlen(term));
                  exit(0);
                  break;
             }
@@ -715,7 +734,8 @@ static void mux_chr_event(void *opaque, int event)
         mux_chr_send_event(d, i, event);
 }
 
-static void mux_chr_update_read_handler(CharDriverState *chr)
+static void mux_chr_update_read_handler(CharDriverState *chr,
+                                        GMainContext *context)
 {
     MuxDriver *d = chr->opaque;
 
@@ -729,8 +749,10 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
     d->chr_event[d->mux_cnt] = chr->chr_event;
     /* Fix up the real driver with mux routines */
     if (d->mux_cnt == 0) {
-        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
-                              mux_chr_event, chr);
+        qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
+                                   mux_chr_read,
+                                   mux_chr_event,
+                                   chr, context);
     }
     if (d->focus != -1) {
         mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
@@ -846,6 +868,7 @@ typedef struct IOWatchPoll
     IOCanReadHandler *fd_can_read;
     GSourceFunc fd_read;
     void *opaque;
+    GMainContext *context;
 } IOWatchPoll;
 
 static IOWatchPoll *io_watch_poll_from_source(GSource *source)
@@ -853,7 +876,8 @@ static IOWatchPoll *io_watch_poll_from_source(GSource *source)
     return container_of(source, IOWatchPoll, parent);
 }
 
-static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
+static gboolean io_watch_poll_prepare(GSource *source,
+                                      gint *timeout_)
 {
     IOWatchPoll *iwp = io_watch_poll_from_source(source);
     bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
@@ -866,7 +890,7 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
         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, NULL);
+        g_source_attach(iwp->src, iwp->context);
     } else {
         g_source_destroy(iwp->src);
         g_source_unref(iwp->src);
@@ -913,19 +937,22 @@ static GSourceFuncs io_watch_poll_funcs = {
 static guint io_add_watch_poll(QIOChannel *ioc,
                                IOCanReadHandler *fd_can_read,
                                QIOChannelFunc fd_read,
-                               gpointer user_data)
+                               gpointer user_data,
+                               GMainContext *context)
 {
     IOWatchPoll *iwp;
     int tag;
 
-    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll));
+    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
+                                       sizeof(IOWatchPoll));
     iwp->fd_can_read = fd_can_read;
     iwp->opaque = user_data;
     iwp->ioc = ioc;
     iwp->fd_read = (GSourceFunc) fd_read;
     iwp->src = NULL;
+    iwp->context = context;
 
-    tag = g_source_attach(&iwp->parent, NULL);
+    tag = g_source_attach(&iwp->parent, context);
     g_source_unref(&iwp->parent);
     return tag;
 }
@@ -1057,7 +1084,8 @@ static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
     return qio_channel_create_watch(s->ioc_out, cond);
 }
 
-static void fd_chr_update_read_handler(CharDriverState *chr)
+static void fd_chr_update_read_handler(CharDriverState *chr,
+                                       GMainContext *context)
 {
     FDCharDriver *s = chr->opaque;
 
@@ -1065,7 +1093,8 @@ static void fd_chr_update_read_handler(CharDriverState *chr)
     if (s->ioc_in) {
         chr->fd_in_tag = io_add_watch_poll(s->ioc_in,
                                            fd_chr_read_poll,
-                                           fd_chr_read, chr);
+                                           fd_chr_read, chr,
+                                           context);
     }
 }
 
@@ -1223,6 +1252,9 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     sigaction(SIGCONT, &act, NULL);
 
     chr = qemu_chr_open_fd(0, 1, common, errp);
+    if (!chr) {
+        return NULL;
+    }
     chr->chr_close = qemu_chr_close_stdio;
     chr->chr_set_echo = qemu_chr_set_echo_stdio;
     if (opts->has_signal) {
@@ -1309,7 +1341,8 @@ static void pty_chr_update_read_handler_locked(CharDriverState *chr)
     }
 }
 
-static void pty_chr_update_read_handler(CharDriverState *chr)
+static void pty_chr_update_read_handler(CharDriverState *chr,
+                                        GMainContext *context)
 {
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_update_read_handler_locked(chr);
@@ -1413,7 +1446,8 @@ static void pty_chr_state(CharDriverState *chr, int connected)
         if (!chr->fd_in_tag) {
             chr->fd_in_tag = io_add_watch_poll(s->ioc,
                                                pty_chr_read_poll,
-                                               pty_chr_read, chr);
+                                               pty_chr_read,
+                                               chr, NULL);
         }
     }
 }
@@ -1679,6 +1713,9 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd,
 
     tty_serial_init(fd, 115200, 'N', 8, 1);
     chr = qemu_chr_open_fd(fd, fd, backend, errp);
+    if (!chr) {
+        return NULL;
+    }
     chr->chr_ioctl = tty_serial_ioctl;
     chr->chr_close = qemu_chr_close_tty;
     return chr;
@@ -2552,7 +2589,8 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     return TRUE;
 }
 
-static void udp_chr_update_read_handler(CharDriverState *chr)
+static void udp_chr_update_read_handler(CharDriverState *chr,
+                                        GMainContext *context)
 {
     NetCharDriver *s = chr->opaque;
 
@@ -2560,7 +2598,8 @@ static void udp_chr_update_read_handler(CharDriverState *chr)
     if (s->ioc) {
         chr->fd_in_tag = io_add_watch_poll(s->ioc,
                                            udp_chr_read_poll,
-                                           udp_chr_read, chr);
+                                           udp_chr_read, chr,
+                                           context);
     }
 }
 
@@ -2963,12 +3002,14 @@ static void tcp_chr_connect(void *opaque)
     if (s->ioc) {
         chr->fd_in_tag = io_add_watch_poll(s->ioc,
                                            tcp_chr_read_poll,
-                                           tcp_chr_read, chr);
+                                           tcp_chr_read,
+                                           chr, NULL);
     }
     qemu_chr_be_generic_open(chr);
 }
 
-static void tcp_chr_update_read_handler(CharDriverState *chr)
+static void tcp_chr_update_read_handler(CharDriverState *chr,
+                                        GMainContext *context)
 {
     TCPCharDriver *s = chr->opaque;
 
@@ -2980,7 +3021,8 @@ static void tcp_chr_update_read_handler(CharDriverState *chr)
     if (s->ioc) {
         chr->fd_in_tag = io_add_watch_poll(s->ioc,
                                            tcp_chr_read_poll,
-                                           tcp_chr_read, chr);
+                                           tcp_chr_read, chr,
+                                           context);
     }
 }
 
@@ -3176,7 +3218,9 @@ static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
     TCPCharDriver *s = chr->opaque;
     QIOChannelSocket *sioc;
 
-    while (!s->connected) {
+    /* It can't wait on s->connected, since it is set asynchronously
+     * in TLS and telnet cases, only wait for an accepted socket */
+    while (!s->ioc) {
         if (s->is_listen) {
             fprintf(stderr, "QEMU waiting for connection on: %s\n",
                     chr->filename);
@@ -3877,16 +3921,26 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     const char *id = qemu_opts_id(opts);
     char *bid = NULL;
 
-    if (id == NULL) {
-        error_setg(errp, "chardev: no id specified");
-        goto err;
-    }
-
     if (qemu_opt_get(opts, "backend") == NULL) {
         error_setg(errp, "chardev: \"%s\" missing backend",
                    qemu_opts_id(opts));
         goto err;
     }
+
+    if (is_help_option(qemu_opt_get(opts, "backend"))) {
+        fprintf(stderr, "Available chardev backend types:\n");
+        for (i = backends; i; i = i->next) {
+            cd = i->data;
+            fprintf(stderr, "%s\n", cd->name);
+        }
+        exit(!is_help_option(qemu_opt_get(opts, "backend")));
+    }
+
+    if (id == NULL) {
+        error_setg(errp, "chardev: no id specified");
+        goto err;
+    }
+
     for (i = backends; i; i = i->next) {
         cd = i->data;
 
@@ -3942,7 +3996,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     }
 
     chr = qemu_chr_find(id);
-    chr->opts = opts;
 
 qapi_out:
     qapi_free_ChardevBackend(backend);
@@ -3951,7 +4004,6 @@ qapi_out:
     return chr;
 
 err:
-    qemu_opts_del(opts);
     return NULL;
 }
 
@@ -3979,6 +4031,7 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
         qemu_chr_fe_claim_no_fail(chr);
         monitor_init(chr, MONITOR_USE_READLINE);
     }
+    qemu_opts_del(opts);
     return chr;
 }
 
@@ -4078,7 +4131,6 @@ static void qemu_chr_free_common(CharDriverState *chr)
 {
     g_free(chr->filename);
     g_free(chr->label);
-    qemu_opts_del(chr->opts);
     if (chr->logfd != -1) {
         close(chr->logfd);
     }
@@ -4459,6 +4511,11 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
 
     s->addr = QAPI_CLONE(SocketAddress, sock->addr);
 
+    qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
+    if (s->is_unix) {
+        qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
+    }
+
     chr->opaque = s;
     chr->chr_wait_connected = tcp_chr_wait_connected;
     chr->chr_write = tcp_chr_write;
@@ -4542,6 +4599,19 @@ static CharDriverState *qmp_chardev_open_udp(const char *id,
     return qemu_chr_open_udp(sioc, common, errp);
 }
 
+
+bool qemu_chr_has_feature(CharDriverState *chr,
+                          CharDriverFeature feature)
+{
+    return test_bit(feature, chr->features);
+}
+
+void qemu_chr_set_feature(CharDriverState *chr,
+                           CharDriverFeature feature)
+{
+    return set_bit(feature, chr->features);
+}
+
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {