[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 |