|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 20/31] libxl_qmp: Introduce libxl__ev_qmp functions
Calling libxl__ev_qmp_register() will prepare a command to be sent to
QEMU and stash it in a queue to be sent later.
The actual sent will be done in a separate patch.
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
tools/libxl/libxl_internal.h | 39 +++++++-
tools/libxl/libxl_qmp.c | 139 +++++++++++++++++++++++++++
tools/libxl/libxl_types_internal.idl | 14 +++
3 files changed, 190 insertions(+), 2 deletions(-)
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 9271701246..16533f651e 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -202,6 +202,8 @@ typedef struct libxl__aop_occurred libxl__aop_occurred;
typedef struct libxl__osevent_hook_nexus libxl__osevent_hook_nexus;
typedef struct libxl__osevent_hook_nexi libxl__osevent_hook_nexi;
typedef struct libxl__ev_qmp_state libxl__ev_qmp_state;
+typedef struct libxl__json_object libxl__json_object;
+typedef struct libxl__carefd libxl__carefd;
typedef struct libxl__domain_create_state libxl__domain_create_state;
typedef void libxl__domain_create_cb(struct libxl__egc *egc,
@@ -357,6 +359,39 @@ struct libxl__ev_child {
LIBXL_LIST_ENTRY(struct libxl__ev_child) entry;
};
+/*
+ * libxl__ev_qmp
+ */
+
+typedef struct libxl__ev_qmp libxl__ev_qmp;
+/* response: QMP response on success, or NULL on error.
+ * error_class: NONE on success, otherwise QMP error class or libxl error */
+typedef void libxl__ev_qmp_callback(libxl__egc *egc, libxl__ev_qmp *ev,
+ const libxl__json_object *response,
+ libxl__qmp_error_class error_class);
+struct libxl__ev_qmp {
+ /* read-only once registered */
+ uint32_t domid;
+ libxl__ev_qmp_callback *callback;
+ /* If !NULL, this file descriptor will be sent to the QMP server,
+ * and closed once sent. */
+ libxl__carefd *efd;
+
+ /* private */
+
+ /* id == -1: initial state or response already received and callback
called.
+ * id > 0: id used to send a command to qemu. */
+ int id;
+ LIBXL_TAILQ_ENTRY(libxl__ev_qmp) entry;
+};
+
+_hidden void libxl__ev_qmp_init(libxl__ev_qmp *ev);
+_hidden int libxl__ev_qmp_register(libxl__gc *gc, libxl__ev_qmp *ev,
+ libxl__ev_qmp_callback *,
+ uint32_t domid,
+ const char *cmd, libxl__json_object *args);
+_hidden void libxl__ev_qmp_deregister(libxl__gc *gc, libxl__ev_qmp *ev);
+_hidden int libxl__ev_qmp_isregistered(const libxl__ev_qmp *ev);
/*
* evgen structures, which are the state we use for generating
@@ -1905,7 +1940,7 @@ typedef enum {
JSON_ANY = 255 /* this is a mask of all values above, adjust as needed
*/
} libxl__json_node_type;
-typedef struct libxl__json_object {
+struct libxl__json_object {
libxl__json_node_type type;
union {
bool b;
@@ -1918,7 +1953,7 @@ typedef struct libxl__json_object {
flexarray_t *map;
} u;
struct libxl__json_object *parent;
-} libxl__json_object;
+};
typedef int (*libxl__json_parse_callback)(libxl__gc *gc,
libxl__json_object *o,
diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index e4441f76f4..9b5eb8fd35 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -1369,15 +1369,57 @@ struct libxl__qmp_rx_buf {
char buf[QMP_RECEIVE_BUFFER_SIZE];
};
+typedef struct libxl__qmp_tx_buf libxl__qmp_tx_buf;
+struct libxl__qmp_tx_buf {
+ LIBXL_TAILQ_ENTRY(libxl__qmp_tx_buf) entry;
+ size_t len;
+ char *buf;
+ /* File descriptor to send along the command */
+ libxl__carefd *efd;
+};
+
struct libxl__ev_qmp_state {
libxl__carefd *cfd;
libxl__ev_fd efd;
uint32_t domid;
LIBXL_TAILQ_HEAD(libxl__qmp_bufs, libxl__qmp_rx_buf) bufs;
+
+ unsigned int last_id_used;
+ /* Indicate that QEMU is ready to respond to command. */
+ bool ready;
+ LIBXL_TAILQ_HEAD(libxl__qmp_tx_bufs, libxl__qmp_tx_buf) tx_buf;
+
+ LIBXL_TAILQ_HEAD(libxl__ev_qmps, libxl__ev_qmp) qmp_events;
};
+/* Prepare a QMP command to be sent */
+static int ev_qmp_queue_command(libxl__gc *gc,
+ libxl__ev_qmp_state *qmp,
+ const char *cmd,
+ const libxl__json_object *args,
+ libxl__carefd *efd)
+{
+ char *buf = NULL;
+ size_t len;
+ libxl__qmp_tx_buf *out;
+
+ buf = qmp_prepare_qmp_cmd(gc,
+ cmd, args, ++qmp->last_id_used,
+ &len);
+ if (!buf)
+ return ERROR_FAIL;
+
+ out = libxl__malloc(NOGC, sizeof(*out));
+ out->buf = buf;
+ out->len = len;
+ out->efd = efd;
+ LIBXL_TAILQ_INSERT_TAIL(&qmp->tx_buf, out, entry);
+
+ return 0;
+}
+
static int ev_qmp_callback_readable(libxl__egc *egc, libxl__ev_qmp_state *qmp,
int fd)
{
@@ -1532,8 +1574,17 @@ static int ev_qmp_callback_readable(libxl__egc *egc,
libxl__ev_qmp_state *qmp,
static void ev_qmp_callback_error(libxl__egc *egc, libxl__ev_qmp_state *qmp)
{
EGC_GC;
+ libxl__ev_qmp *ev, *tev;
LOGD(ERROR, qmp->domid, "Error happend with the QMP connection to QEMU");
+
+ LIBXL_TAILQ_FOREACH_SAFE(ev, &qmp->qmp_events, entry, tev) {
+ if (ev->id == -1)
+ continue;
+ /* Call every callback with error state. */
+ ev->id = -1;
+ ev->callback(egc, ev, NULL, LIBXL__QMP_ERROR_CLASS_LIBXL_ERROR);
+ }
libxl__ev_qmp_stop(gc, qmp);
}
@@ -1574,6 +1625,10 @@ static void libxl__ev_qmp_state_init(libxl__ev_qmp_state
*qmp)
qmp->cfd = NULL;
libxl__ev_fd_init(&qmp->efd);
LIBXL_TAILQ_INIT(&qmp->bufs);
+ qmp->last_id_used = 0;
+ qmp->ready = false;
+ LIBXL_TAILQ_INIT(&qmp->tx_buf);
+ LIBXL_TAILQ_INIT(&qmp->qmp_events);
}
libxl__ev_qmp_state *libxl__ev_qmp_start(libxl__gc *gc, uint32_t domid)
@@ -1650,6 +1705,8 @@ out:
void libxl__ev_qmp_stop(libxl__gc *gc, libxl__ev_qmp_state *qmp)
{
libxl__qmp_rx_buf *buf, *tbuf;
+ libxl__qmp_tx_buf *tx_buf, *tx_tbuf;
+ libxl__ev_qmp *qmp_ev, *tqmp_ev;
if (!qmp)
return;
@@ -1661,6 +1718,19 @@ void libxl__ev_qmp_stop(libxl__gc *gc,
libxl__ev_qmp_state *qmp)
LIBXL_TAILQ_FOREACH_SAFE(buf, &qmp->bufs, entry, tbuf)
free(buf);
LIBXL_TAILQ_INIT(&qmp->bufs);
+ LIBXL_TAILQ_FOREACH_SAFE(tx_buf, &qmp->tx_buf, entry, tx_tbuf) {
+ free(tx_buf->buf);
+ free(tx_buf);
+ }
+ LIBXL_TAILQ_INIT(&qmp->tx_buf);
+
+ LIBXL_TAILQ_FOREACH_SAFE(qmp_ev, &qmp->qmp_events, entry, tqmp_ev) {
+ LOGD(ERROR, qmp->domid, "Event left %p", qmp_ev);
+ libxl__ev_qmp_deregister(gc, qmp_ev);
+ }
+ LIBXL_TAILQ_INIT(&qmp->qmp_events);
+
+ qmp->ready = false;
libxl__ev_fd_deregister(gc, &qmp->efd);
libxl__carefd_close(qmp->cfd);
@@ -1668,6 +1738,75 @@ void libxl__ev_qmp_stop(libxl__gc *gc,
libxl__ev_qmp_state *qmp)
CTX_UNLOCK;
}
+
+/*
+ * Actual libxl__ev_qmp
+ */
+
+void libxl__ev_qmp_init(libxl__ev_qmp *ev)
+{
+ ev->domid = INVALID_DOMID;
+ ev->callback = NULL;
+ ev->efd = NULL;
+ ev->id = -1;
+}
+
+int libxl__ev_qmp_register(libxl__gc *gc, libxl__ev_qmp *ev,
+ libxl__ev_qmp_callback *callback,
+ uint32_t domid,
+ const char *cmd, libxl__json_object *args)
+{
+ libxl__ev_qmp_state *qmp;
+ int rc;
+
+ CTX_LOCK;
+
+ LOGD(DEBUG, domid, " ev %p, cmd '%s'", ev, cmd);
+
+ /* Connect to QEMU if not already connected */
+ qmp = libxl__ev_qmp_start(gc, domid);
+ if (!qmp) {
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ rc = ev_qmp_queue_command(gc, qmp, cmd, args, ev->efd);
+ if (rc)
+ goto out;
+
+ ev->domid = domid;
+ ev->callback = callback;
+ ev->id = qmp->last_id_used;
+ /* fd is in the queue, and should be closed once sent */
+ ev->efd = NULL;
+
+ LIBXL_TAILQ_INSERT_TAIL(&qmp->qmp_events, ev, entry);
+
+ rc = 0;
+
+out:
+ CTX_UNLOCK;
+ return rc;
+}
+
+void libxl__ev_qmp_deregister(libxl__gc *gc, libxl__ev_qmp *ev)
+{
+ LOGD(DEBUG, ev->domid, " ev %p", ev);
+
+ CTX_LOCK;
+
+ if (libxl__ev_qmp_isregistered(ev)) {
+ LIBXL_TAILQ_REMOVE(&CTX->qmp_ev->qmp_events, ev, entry);
+ }
+ libxl__ev_qmp_init(ev);
+
+ CTX_UNLOCK;
+}
+
+int libxl__ev_qmp_isregistered(const libxl__ev_qmp *ev)
+{
+ return ev->domid != INVALID_DOMID;
+}
/*
* Local variables:
* mode: C
diff --git a/tools/libxl/libxl_types_internal.idl
b/tools/libxl/libxl_types_internal.idl
index f2ff01718d..ada97615d5 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -13,6 +13,20 @@ libxl__qmp_message_type = Enumeration("qmp_message_type", [
(5, "invalid"),
])
+libxl__qmp_error_class = Enumeration("qmp_error_class", [
+ # No error
+ (0, "NONE"),
+ # Error generated by libxl (e.g. socket closed unexpectedly, no mem, ...)
+ (1, "libxl_error"),
+ # QMP error classes described in QEMU sources code (QapiErrorClass)
+ (2, "GenericError"),
+ (3, "CommandNotFound"),
+ (4, "DeviceNotActive"),
+ (5, "DeviceNotFound"),
+ # Unrecognized QMP error class
+ (6, "Unknown"),
+ ])
+
libxl__device_kind = Enumeration("device_kind", [
(0, "NONE"),
(1, "VIF"),
--
Anthony PERARD
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |