All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori@us.ibm.com>
To: qemu-devel@nongnu.org
Cc: Anthony Liguori <aliguori@us.ibm.com>
Subject: [Qemu-devel] [PATCH 17/21] qom: add CharDriver class
Date: Sun, 24 Jul 2011 20:44:49 -0500	[thread overview]
Message-ID: <1311558293-5855-18-git-send-email-aliguori@us.ibm.com> (raw)
In-Reply-To: <1311558293-5855-1-git-send-email-aliguori@us.ibm.com>

The CharDriver type replaces the CharDriverState in QEMU today.  Here's how
everything matches up:

 1) qemu_chr_open() no longer exists.  This function used to act as a factory
    and used parsing of the filename to determine which type to create.  A newer
    version using QemuOpts was introduced, qemu_chr_open_opts() which eliminates
    the filename in favor of typed key value pairs.

    Now, plug_create() can be used to create CharDrivers using an explicit
    type that subclasses CharDriver.

 2) query-chardev is deprecated.  This is replaced by
    plug_list(type=char-driver) and plug_list_props().

 3) We can now dynamically add and remove new CharDrivers

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 Makefile.qom          |    3 +
 Qconfig               |    1 +
 chrdrv/Makefile       |    1 +
 chrdrv/Qconfig        |    5 +
 chrdrv/chrdrv.c       |  229 ++++++++++++++++++++++++++++++++++++++++
 configure             |    2 +-
 include/qemu/chrdrv.h |  281 +++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 521 insertions(+), 1 deletions(-)
 create mode 100644 chrdrv/Makefile
 create mode 100644 chrdrv/Qconfig
 create mode 100644 chrdrv/chrdrv.c
 create mode 100644 include/qemu/chrdrv.h

diff --git a/Makefile.qom b/Makefile.qom
index c694cbb..02a5ca5 100644
--- a/Makefile.qom
+++ b/Makefile.qom
@@ -16,3 +16,6 @@ common-obj-y += $(addprefix qom/,$(qom-obj-y))
 include $(SRC_PATH)/devices/Makefile
 common-obj-y += $(addprefix devices/,$(devices-obj-y))
 
+include $(SRC_PATH)/chrdrv/Makefile
+common-obj-y += $(addprefix chrdrv/,$(chrdrv-obj-y))
+
diff --git a/Qconfig b/Qconfig
index 03f2a87..57c1c7d 100644
--- a/Qconfig
+++ b/Qconfig
@@ -1,3 +1,4 @@
 source qapi/Qconfig
 source qom/Qconfig
 source devices/Qconfig
+source chrdrv/Qconfig
diff --git a/chrdrv/Makefile b/chrdrv/Makefile
new file mode 100644
index 0000000..43a51e7
--- /dev/null
+++ b/chrdrv/Makefile
@@ -0,0 +1 @@
+chrdrv-obj-$(CONFIG_CHRDRV) := chrdrv.o
diff --git a/chrdrv/Qconfig b/chrdrv/Qconfig
new file mode 100644
index 0000000..845c205
--- /dev/null
+++ b/chrdrv/Qconfig
@@ -0,0 +1,5 @@
+config CHRDRV
+       bool "QEMU Character Drivers"
+       default y
+       help
+         Character layer
diff --git a/chrdrv/chrdrv.c b/chrdrv/chrdrv.c
new file mode 100644
index 0000000..a9b8dc2
--- /dev/null
+++ b/chrdrv/chrdrv.c
@@ -0,0 +1,229 @@
+#include "qemu/chrdrv.h"
+
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    return cdc->write(s, buf, len);
+}
+
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    return cdc->ioctl(s, cmd, arg);
+}
+
+int char_driver_get_msgfd(CharDriver *s)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    return cdc->get_msgfd(s);
+}
+
+void char_driver_send_event(CharDriver *s, int event)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    cdc->send_event(s, event);
+}
+
+void char_driver_accept_input(CharDriver *s)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    cdc->accept_input(s);
+}
+
+void char_driver_set_echo(CharDriver *s, bool echo)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    cdc->set_echo(s, echo);
+}
+
+void char_driver_guest_open(CharDriver *s)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    cdc->guest_open(s);
+}
+
+void char_driver_guest_close(CharDriver *s)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    cdc->guest_close(s);
+}
+
+static int char_driver_def_write(CharDriver *s, const uint8_t *buf, int len)
+{
+    return -ENOTSUP;
+}
+
+static void char_driver_def_update_read_handler(CharDriver *s)
+{
+}
+
+static int char_driver_def_ioctl(CharDriver *s, int cmd, void *arg)
+{
+    return -ENOTSUP;
+}
+
+static int char_driver_def_get_msgfd(CharDriver *s)
+{
+    return -1;
+}
+
+static void char_driver_def_send_event(CharDriver *chr, int event)
+{
+}
+
+static void char_driver_def_close(CharDriver *chr)
+{
+    char_driver_send_event(chr, CHR_EVENT_CLOSED);
+}
+
+static void char_driver_def_accept_input(CharDriver *chr)
+{
+}
+
+static void char_driver_def_set_echo(CharDriver *chr, bool echo)
+{
+}
+
+static void char_driver_def_guest_open(CharDriver *chr)
+{
+}
+
+static void char_driver_def_guest_close(CharDriver *chr)
+{
+}
+
+static void char_driver_def_open(CharDriver *chr, Error **errp)
+{
+}
+
+static void char_driver_realize(Plug *plug)
+{
+    CharDriver *chr = CHAR_DRIVER(plug);
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+    cdc->open(chr, NULL);
+}
+
+int char_driver_can_read(CharDriver *chr)
+{
+    if (!chr->chr_can_read) {
+        return 1024;
+    }
+
+    return chr->chr_can_read(chr->handler_opaque);
+}
+
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len)
+{
+    if (!chr->chr_read) {
+        return;
+    }
+
+    chr->chr_read(chr->handler_opaque, buf, len);
+}
+
+void char_driver_event(CharDriver *chr, int event)
+{
+    /* Keep track if the char device is open */
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        chr->opened = 1;
+        break;
+    case CHR_EVENT_CLOSED:
+        chr->opened = 0;
+        break;
+    }
+
+    if (!chr->chr_event) {
+        return;
+    }
+
+    chr->chr_event(chr->handler_opaque, event);
+}
+
+static void char_driver_class_init(TypeClass *class)
+{
+    PlugClass *pc = PLUG_CLASS(class);
+    CharDriverClass *cdc = CHAR_DRIVER_CLASS(class);
+
+    pc->realize = char_driver_realize;
+    cdc->write = char_driver_def_write;
+    cdc->ioctl = char_driver_def_ioctl;
+    cdc->get_msgfd = char_driver_def_get_msgfd;
+    cdc->send_event = char_driver_def_send_event;
+    cdc->close = char_driver_def_close;
+    cdc->accept_input = char_driver_def_accept_input;
+    cdc->set_echo = char_driver_def_set_echo;
+    cdc->guest_open = char_driver_def_guest_open;
+    cdc->guest_close = char_driver_def_guest_close;
+    cdc->open = char_driver_def_open;
+    cdc->update_read_handler = char_driver_def_update_read_handler;
+
+}
+
+static void char_driver_generic_open(CharDriver *s)
+{
+    char_driver_event(s, CHR_EVENT_OPENED);
+}
+
+void char_driver_add_handlers(CharDriver *s,
+                              IOCanReadHandler *fd_can_read,
+                              IOReadHandler *fd_read,
+                              IOEventHandler *fd_event,
+                              void *opaque)
+{
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        /* chr driver being released. */
+        ++s->avail_connections;
+    }
+    s->chr_can_read = fd_can_read;
+    s->chr_read = fd_read;
+    s->chr_event = fd_event;
+    s->handler_opaque = opaque;
+    if (cdc->update_read_handler) {
+        cdc->update_read_handler(s);
+    }
+
+    /* We're connecting to an already opened device, so let's make sure we
+       also get the open event */
+    if (s->opened) {
+        char_driver_generic_open(s);
+    }
+}
+
+static void char_driver_fini(TypeInstance *inst)
+{
+    CharDriver *chr = CHAR_DRIVER(inst);
+    CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+    if (cdc->close) {
+        cdc->close(chr);
+    }
+}
+
+static TypeInfo chrdrv_type_info = {
+    .name = TYPE_CHAR_DRIVER,
+    .parent = TYPE_PLUG,
+    .instance_size = sizeof(CharDriver),
+    .instance_finalize = char_driver_fini,
+    .class_size = sizeof(CharDriverClass),
+    .class_init = char_driver_class_init,
+    .abstract = true,
+};
+
+static void register_backends(void)
+{
+    type_register_static(&chrdrv_type_info);
+}
+
+device_init(register_backends);
diff --git a/configure b/configure
index 6ec1020..63c62b0 100755
--- a/configure
+++ b/configure
@@ -3516,7 +3516,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
 DIRS="$DIRS qapi"
-DIRS="$DIRS qga qom devices"
+DIRS="$DIRS qga qom devices chrdrv"
 FILES="Makefile tests/Makefile"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/chrdrv.h b/include/qemu/chrdrv.h
new file mode 100644
index 0000000..075b589
--- /dev/null
+++ b/include/qemu/chrdrv.h
@@ -0,0 +1,281 @@
+#ifndef QEMU_CHAR_DRIVER
+#define QEMU_CHAR_DRIVER
+
+#include "qemu/plug.h"
+
+/* Temporarily for a couple of enum */
+#include "qemu-char.h"
+
+/**
+ * @CharDriver
+ *
+ * A streaming data connection, typically used to transfer data from a @Device
+ * to some process on the host.
+ *
+ * A @CharDriver subclass implements the driver.  Typically, this is the host
+ * routine and may include a TCP, stdio, or fd transport.  The @Device that is
+ * interacting with the driver is the client.  This is typically a device that
+ * looks like a serial port including UARTs, virtio-serial, etc.
+ *
+ * @CharDriver also supports by direction messaging.  These messages carry no
+ * data though.
+ */
+typedef struct CharDriver
+{
+    Plug parent;
+
+    /* Public */
+
+    /**
+     * @avail_connection used by qdev to keep track of how "connections" are
+     * available in the @CharDriver verses how many qdev are using.  This is
+     * meant to ensure that the same @CharDriver isn't connected to multiple
+     * sockets at the same time.
+     *
+     * It's not well thought through though as there are other things that can
+     * use a @CharDriver and the attempt at supporting mux drivers results in
+     * this value just being ignored for mux (although not predictably).
+     *
+     * Sufficed to say, this needs to go away.
+     */
+    int avail_connections;
+
+    /**
+     * @opened despite what the name implies, this doesn't correspond to whether
+     * the @CharDriver is opened.  @CharDriver doesn't have a notion of opened,
+     * instead, @opened tracks whether the CHR_EVENT_OPEN event has been
+     * generated.  The CHR_EVENT_CLOSED event will clear the @opened flag.
+     *
+     * The primary purpose of this flag is to ensure the CHR_EVENT_OPEN event is
+     * not generated twice in a row.
+     */
+    int opened;
+
+    /* Private */
+
+    /**
+     * @chr_can_read when a client has added its handlers to a @CharDriver, this
+     * contains the can read callback for the client.
+     */
+    IOCanReadHandler *chr_can_read;
+
+    /**
+     * @chr_read when a client has added its handlers to a @CharDriver, this
+     * contains the read callback for the client.
+     */
+    IOReadHandler *chr_read;
+
+    /**
+     * @chr_event when a client has added its handlers to a @CharDriver, this
+     * contains the event callback for the client.
+     */
+    IOEventHandler *chr_event;
+
+    /**
+     * @handler_opaque when a client has added its handlers to a @CharDriver,
+     * this contains the opaque associated with the callbacks for the client.
+     */
+    void *handler_opaque;
+} CharDriver;
+
+typedef struct CharDriverClass
+{
+    PlugClass parent_class;
+
+    /* Public */
+    int (*write)(CharDriver *s, const uint8_t *buf, int len);
+    int (*ioctl)(CharDriver *s, int cmd, void *arg);
+    int (*get_msgfd)(CharDriver *s);
+    void (*send_event)(CharDriver *chr, int event);
+    void (*accept_input)(CharDriver *chr);
+    void (*set_echo)(CharDriver *chr, bool echo);
+    void (*guest_open)(CharDriver *chr);
+    void (*guest_close)(CharDriver *chr);
+
+    /* Protected */
+    /**
+     * @open:
+     *
+     * This is called during realize to initialize the object.  At this point,
+     * all of the properties should have been set.
+     */
+    void (*open)(CharDriver *s, Error **errp);
+
+    /**
+     * @update_read_handler:
+     *
+     * This is called after @char_driver_add_handlers is called to allow sub-
+     * classes to re-register their callbacks if necessary.
+     */
+    void (*update_read_handler)(CharDriver *s);
+
+    /**
+     * @close:
+     *
+     * Called during the finalize path.  The default behavior sends a
+     * CHR_EVENT_CLOSED.  It's generally better to use the classes destructor to
+     * implement driver specific cleanup.
+     */
+    void (*close)(CharDriver *chr);
+} CharDriverClass;
+
+#define TYPE_CHAR_DRIVER "char-driver"
+#define CHAR_DRIVER(obj) TYPE_CHECK(CharDriver, obj, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_CLASS(class) \
+    TYPE_CLASS_CHECK(CharDriverClass, class, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_GET_CLASS(obj) \
+    TYPE_GET_CLASS(CharDriverClass, obj, TYPE_CHAR_DRIVER)
+
+/**
+ * @char_driver_write:
+ *
+ * Write data to a @CharDriver
+ *
+ * @buf      The data to write
+ * @len      The size of the data in buf
+ *
+ * Returns:  The number of bytes written to the device
+ *
+ * Notes:    Each backend deals with flow control on its own.  Depending on the
+ *           driver, this function may block execution or silently drop data.
+ *
+ *           Dropping data may also occur if the backend uses a connection
+ *           oriented transport and the transport is disconnected.
+ *
+ *           The caller receives no indication that data was dropped.  This
+ *           function may return a partial write result.
+ */
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len);
+
+/**
+ * @char_driver_ioctl:
+ *
+ * Performs a device specific ioctl.
+ *
+ * @cmd      an ioctl, see CHR_IOCTL_*
+ * @arg      values depends on @cmd
+ *
+ * Returns:  The result of this depends on the @cmd.  If @cmd is not supported
+ *           by this device, -ENOTSUP.
+ */
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg);
+
+/**
+ * @char_driver_get_msgfd:
+ *
+ * If the driver has received a file descriptor through its transport, this
+ * function will return the file descriptor.
+ *
+ * Returns:  The file descriptor or -1 if transport doesn't support file
+ *           descriptor passing or doesn't currently have a file descriptor.
+ */
+int char_driver_get_msgfd(CharDriver *s);
+
+/**
+ * @char_driver_send_event:
+ *
+ * Raise an event to a driver.
+ *
+ * @event  see CHR_EVENT_*
+ *
+ * Notes:  There is no way to determine if the driver successfully handled the
+ *         event.
+ */
+void char_driver_send_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_accept_input:
+ *
+ * I honestly can't tell what this function is meant to do.
+ */
+void char_driver_accept_input(CharDriver *chr);
+
+/**
+ * @char_driver_set_echo:
+ *
+ * Requests to override the backends use of echo.  This is really only
+ * applicable to the stdio backend but is a generic interface today.
+ *
+ * @echo true to enable echo
+ */
+void char_driver_set_echo(CharDriver *chr, bool echo);
+
+/**
+ * @char_driver_guest_open:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is created.
+ *
+ * Note:  There is no way to determine if a client has the notion of a
+ *        connection.  A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_open(CharDriver *chr);
+
+/**
+ * @char_driver_guest_close:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is closed.
+ *
+ * Note:  There is no way to determine if a client has the notion of a
+ *        connection.  A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_close(CharDriver *chr);
+
+/**
+ * @char_driver_can_read:
+ *
+ * Returns:  The maximum number of bytes the client connected to the driver can
+ *           receive at the moment.
+ */
+int char_driver_can_read(CharDriver *chr);
+
+/**
+ * @char_driver_read:
+ *
+ * This function transfers the contents of buf to the client.
+ *
+ * @buf  the buffer to write to the client
+ * @len  the number of bytes to write
+ *
+ * Notes:  This function should only be invoked after receiving a non-zero
+ *         value from @char_driver_can_read.  @len may be larger than the return
+ *         value but the results are undefined.  It may result in the entire
+ *         message being dropped or the message being truncated.
+ */
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len);
+
+/**
+ * @char_driver_event:
+ *
+ * Sends an event to the client of a driver.
+ *
+ * @event  the CHR_EVENT_* to send to the client
+ */
+void char_driver_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_add_handlers:
+ *
+ * Connect a client to a @CharDriver.  A connected client may send data to the
+ * driver by using the @char_driver_write function.  Data is received from the
+ * driver to the client using the callbacks registered in this function.
+ *
+ * @fd_can_read  This callback returns the maximum amount of data the client is
+ *               prepared to receive from the driver.
+ *
+ * @fd_read      This callback is used by the driver to pass data to the client.
+ *
+ * @fd_event     This callback is used to send events from the driver to the
+ *               client.
+ *
+ * @opaque       An opaque value that is passed with the registered callbacks to
+ *               form a closure.
+ */
+void char_driver_add_handlers(CharDriver *s,
+                              IOCanReadHandler *fd_can_read,
+                              IOReadHandler *fd_read,
+                              IOEventHandler *fd_event,
+                              void *opaque);
+
+#endif
-- 
1.7.4.1

  parent reply	other threads:[~2011-07-25  1:45 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-25  1:44 [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 01/21] qom: add make infrastructure Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 02/21] qom: convert QAPI to use Qconfig build system Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 03/21] qom: Add core type system Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 04/21] qom: add Plug class Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 05/21] plug: add Plug property type Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 06/21] plug: add socket " Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 07/21] plug: add generated property types Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 08/21] qom: add plug_create QMP command Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 09/21] qom: add plug_list " Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 10/21] qom: add plug_get " Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 11/21] qom: add plug_set " Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 12/21] qom: add plug_list_props " Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 13/21] qom: add plug_destroy command Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 14/21] qom: add example qsh command Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 15/21] qom: add Device class Anthony Liguori
2011-07-27 15:10   ` Peter Maydell
2011-07-27 16:07     ` Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 16/21] qom-devices: add a Pin class Anthony Liguori
2011-07-25  1:44 ` Anthony Liguori [this message]
2011-07-25  1:44 ` [Qemu-devel] [PATCH 18/21] qom-chrdrv: add memory character driver Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 19/21] qom-chrdrv: add Socket base class Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 20/21] qom-chrdrv: add TCPServer class Anthony Liguori
2011-07-25  1:44 ` [Qemu-devel] [PATCH 21/21] qom-chrdrv: add UnixServer Anthony Liguori
2011-07-25 11:21 ` [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model Kevin Wolf
2011-07-25 12:45   ` Anthony Liguori
2011-07-25 13:08     ` Kevin Wolf
2011-07-25 13:10       ` Anthony Liguori
2011-07-26 12:59 ` Paolo Bonzini
2011-07-26 14:02   ` Anthony Liguori
2011-07-26 14:35     ` Paolo Bonzini
2011-07-26 15:34       ` Anthony Liguori
2011-07-26 18:26         ` Paolo Bonzini
2011-07-26 19:23           ` Anthony Liguori
2011-07-27  8:55             ` Paolo Bonzini
2011-07-27 12:48               ` Anthony Liguori
2011-07-27 15:33                 ` Paolo Bonzini
2011-07-27 16:19                   ` Anthony Liguori
2011-07-27 16:28                   ` Anthony Liguori
2011-07-27 18:51                     ` Paolo Bonzini
2011-07-27 20:01                       ` Anthony Liguori
2011-07-28  7:36                         ` Paolo Bonzini
2011-07-28 12:46                           ` Anthony Liguori
2011-07-28 13:50                             ` Paolo Bonzini
2011-07-28 14:03                               ` Anthony Liguori
2011-07-28 14:41                                 ` Paolo Bonzini
2011-07-28 15:04                                   ` Anthony Liguori
2011-07-28 15:47                                     ` Paolo Bonzini
2011-07-28 17:59                                       ` Anthony Liguori
2011-07-29  7:19                                         ` Paolo Bonzini
2011-07-27 21:33     ` Peter Maydell
2011-07-27 22:31       ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1311558293-5855-18-git-send-email-aliguori@us.ibm.com \
    --to=aliguori@us.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.