[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Re: [PATCH RESEND V8 7/7] libxl: Introduce a QMP client
On Wed, 2011-09-21 at 13:59 +0100, Anthony PERARD wrote: > QMP stands for QEMU Monitor Protocol and it is used to query information > from QEMU or to control QEMU. > > This implementation will ask QEMU the list of chardevice and store the > path to serial ports in xenstored. So we will be able to use xl console > with QEMU upstream. > > In order to connect to the QMP server, a socket file is created in > /var/run/xen/qmp-libxl-$(domid). > > Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> Again I didn't fully review but I remember being happy with it lasttime so: Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx> > --- > tools/libxl/Makefile | 2 +- > tools/libxl/libxl.c | 2 + > tools/libxl/libxl_create.c | 4 + > tools/libxl/libxl_dm.c | 10 + > tools/libxl/libxl_internal.h | 19 ++ > tools/libxl/libxl_qmp.c | 587 > ++++++++++++++++++++++++++++++++++++++++++ > 6 files changed, 623 insertions(+), 1 deletions(-) > create mode 100644 tools/libxl/libxl_qmp.c > > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > index e50874e..f10c7e8 100644 > --- a/tools/libxl/Makefile > +++ b/tools/libxl/Makefile > @@ -37,7 +37,7 @@ LIBXL_LIBS += -lyajl > LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \ > libxl_dom.o libxl_exec.o libxl_xshelp.o > libxl_device.o \ > libxl_internal.o libxl_utils.o libxl_uuid.o > libxl_json.o \ > - $(LIBXL_OBJS-y) > + libxl_qmp.o $(LIBXL_OBJS-y) > LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o > > $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) > $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index 426058f..fbd522d 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -762,6 +762,8 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, > int force) > if (dm_present) { > if (libxl__destroy_device_model(&gc, domid) < 0) > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl__destroy_device_model > failed for %d", domid); > + > + libxl__qmp_cleanup(&gc, domid); > } > if (libxl__devices_destroy(&gc, domid, force) < 0) > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_destroy_devices failed for > %d", domid); > diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c > index ce76729..c97819a 100644 > --- a/tools/libxl/libxl_create.c > +++ b/tools/libxl/libxl_create.c > @@ -573,6 +573,10 @@ static int do_domain_create(libxl__gc *gc, > libxl_domain_config *d_config, > } > > if (dm_starting) { > + if (dm_info->device_model_version > + == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) { > + libxl__qmp_initializations(ctx, domid); > + } > ret = libxl__confirm_device_model_startup(gc, dm_starting); > if (ret < 0) { > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, > diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c > index e854a50..ef09079 100644 > --- a/tools/libxl/libxl_dm.c > +++ b/tools/libxl/libxl_dm.c > @@ -248,6 +248,16 @@ static char ** > libxl__build_device_model_args_new(libxl__gc *gc, > flexarray_vappend(dm_args, dm, > "-xen-domid", libxl__sprintf(gc, "%d", info->domid), > NULL); > > + flexarray_append(dm_args, "-chardev"); > + flexarray_append(dm_args, > + libxl__sprintf(gc, "socket,id=libxl-cmd," > + "path=%s/qmp-libxl-%d,server,nowait", > + libxl_run_dir_path(), > + info->domid)); > + > + flexarray_append(dm_args, "-mon"); > + flexarray_append(dm_args, "chardev=libxl-cmd,mode=control"); > + > if (info->type == LIBXL_DOMAIN_TYPE_PV) { > flexarray_append(dm_args, "-xen-attach"); > } > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index f495e86..2ea1582 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -387,6 +387,25 @@ _hidden int libxl__e820_alloc(libxl_ctx *ctx, uint32_t > domid, libxl_domain_confi > #define STRINGIFY(x) #x > #define TOSTRING(x) STRINGIFY(x) > > +/* from libxl_qmp */ > +typedef struct libxl__qmp_handler libxl__qmp_handler; > + > +/* Initialise and connect to the QMP socket. > + * Return an handler or NULL if there is an error > + */ > +_hidden libxl__qmp_handler *libxl__qmp_initialize(libxl_ctx *ctx, > + uint32_t domid); > +/* ask to QEMU the serial port information and store it in xenstore. */ > +_hidden int libxl__qmp_query_serial(libxl__qmp_handler *qmp); > +/* close and free the QMP handler */ > +_hidden void libxl__qmp_close(libxl__qmp_handler *qmp); > +/* remove the socket file, if the file has already been removed, > + * nothing happen */ > +_hidden void libxl__qmp_cleanup(libxl__gc *gc, uint32_t domid); > + > +/* this helper calls qmp_initialize, query_serial and qmp_close */ > +_hidden int libxl__qmp_initializations(libxl_ctx *ctx, uint32_t domid); > + > /* from libxl_json */ > #include <yajl/yajl_gen.h> > > diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c > new file mode 100644 > index 0000000..6e8ecea > --- /dev/null > +++ b/tools/libxl/libxl_qmp.c > @@ -0,0 +1,587 @@ > +/* > + * Copyright (C) 2011 Citrix Ltd. > + * Author Anthony PERARD <anthony.perard@xxxxxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU Lesser General Public License as published > + * by the Free Software Foundation; version 2.1 only. with the special > + * exception on linking described in file LICENSE. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU Lesser General Public License for more details. > + */ > + > +/* > + * This file implement a client for QMP (QEMU Monitor Protocol). For the > + * Specification, see in the QEMU repository. > + */ > + > +#include <unistd.h> > +#include <sys/un.h> > +#include <sys/queue.h> > + > +#include <yajl/yajl_gen.h> > + > +#include "libxl_internal.h" > + > +/* #define DEBUG_RECEIVED */ > + > +#ifdef DEBUG_RECEIVED > +# define DEBUG_REPORT_RECEIVED(buf, len) \ > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "received: '%.*s'", len, buf) > +#else > +# define DEBUG_REPORT_RECEIVED(buf, len) ((void)0) > +#endif > + > +/* > + * QMP types & constant > + */ > + > +#define QMP_RECEIVE_BUFFER_SIZE 4096 > + > +typedef int (*qmp_callback_t)(libxl__qmp_handler *qmp, > + const libxl__json_object *tree); > + > +typedef struct callback_id_pair { > + int id; > + qmp_callback_t callback; > + SIMPLEQ_ENTRY(callback_id_pair) next; > +} callback_id_pair; > + > +struct libxl__qmp_handler { > + struct sockaddr_un addr; > + int qmp_fd; > + bool connected; > + time_t timeout; > + /* wait_for_id will be used by the synchronous send function */ > + int wait_for_id; > + > + char buffer[QMP_RECEIVE_BUFFER_SIZE]; > + libxl__yajl_ctx *yajl_ctx; > + > + libxl_ctx *ctx; > + uint32_t domid; > + > + int last_id_used; > + SIMPLEQ_HEAD(callback_list, callback_id_pair) callback_list; > +}; > + > +static int qmp_send(libxl__qmp_handler *qmp, > + const char *cmd, qmp_callback_t callback); > + > +static const int QMP_SOCKET_CONNECT_TIMEOUT = 5; > + > +/* > + * QMP callbacks functions > + */ > + > +static int store_serial_port_info(libxl__qmp_handler *qmp, > + const char *chardev, > + int port) > +{ > + libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); > + char *path = NULL; > + int ret = 0; > + > + if (!(chardev && strncmp("pty:", chardev, 4) == 0)) { > + return -1; > + } > + > + path = libxl__xs_get_dompath(&gc, qmp->domid); > + path = libxl__sprintf(&gc, "%s/serial/%d/tty", path, port); > + > + ret = libxl__xs_write(&gc, XBT_NULL, path, "%s", chardev + 4); > + > + libxl__free_all(&gc); > + return ret; > +} > + > +static int register_serials_chardev_callback(libxl__qmp_handler *qmp, > + const libxl__json_object *o) > +{ > + const libxl__json_object *obj = NULL; > + const libxl__json_object *label = NULL; > + const char *s = NULL; > + int i = 0; > + const char *chardev = NULL; > + int ret = 0; > + > + for (i = 0; (obj = libxl__json_array_get(o, i)); i++) { > + if (!libxl__json_object_is_map(obj)) > + continue; > + label = libxl__json_map_get("label", obj, JSON_STRING); > + s = libxl__json_object_get_string(label); > + > + if (s && strncmp("serial", s, strlen("serial")) == 0) { > + const libxl__json_object *filename = NULL; > + char *endptr = NULL; > + int port_number; > + > + filename = libxl__json_map_get("filename", obj, JSON_STRING); > + chardev = libxl__json_object_get_string(filename); > + > + s += strlen("serial"); > + port_number = strtol(s, &endptr, 10); > + if (*s == 0 || *endptr != 0) { > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, > + "Invalid serial port number: %s", s); > + return -1; > + } > + ret = store_serial_port_info(qmp, chardev, port_number); > + if (ret) { > + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, > + "Failed to store serial port information" > + " in xenstore"); > + return ret; > + } > + } > + }; > + > + return ret; > +} > + > +static int qmp_capabilities_callback(libxl__qmp_handler *qmp, > + const libxl__json_object *o) > +{ > + qmp->connected = true; > + > + return 0; > +} > + > +/* > + * QMP commands > + */ > + > +static int enable_qmp_capabilities(libxl__qmp_handler *qmp) > +{ > + return qmp_send(qmp, "qmp_capabilities", qmp_capabilities_callback); > +} > + > +/* > + * Helpers > + */ > + > +static libxl__qmp_message_type qmp_response_type(libxl__qmp_handler *qmp, > + const libxl__json_object *o) > +{ > + libxl__qmp_message_type type; > + libxl__json_map_node *node = NULL; > + int i = 0; > + > + for (i = 0; (node = libxl__json_map_node_get(o, i)); i++) { > + if (libxl__qmp_message_type_from_string(node->map_key, &type) == 0) > + return type; > + } > + > + return LIBXL__QMP_MESSAGE_TYPE_INVALID; > +} > + > +static callback_id_pair *qmp_get_callback_from_id(libxl__qmp_handler *qmp, > + const libxl__json_object > *o) > +{ > + const libxl__json_object *id_object = libxl__json_map_get("id", o, > + JSON_INTEGER); > + int id = -1; > + callback_id_pair *pp = NULL; > + > + if (id_object) { > + id = libxl__json_object_get_integer(id_object); > + > + SIMPLEQ_FOREACH(pp, &qmp->callback_list, next) { > + if (pp->id == id) { > + return pp; > + } > + } > + } > + return NULL; > +} > + > +static void qmp_handle_error_response(libxl__qmp_handler *qmp, > + const libxl__json_object *resp) > +{ > + callback_id_pair *pp = qmp_get_callback_from_id(qmp, resp); > + > + resp = libxl__json_map_get("error", resp, JSON_MAP); > + resp = libxl__json_map_get("desc", resp, JSON_STRING); > + > + if (pp) { > + pp->callback(qmp, NULL); > + if (pp->id == qmp->wait_for_id) { > + /* tell that the id have been processed */ > + qmp->wait_for_id = 0; > + } > + SIMPLEQ_REMOVE(&qmp->callback_list, pp, callback_id_pair, next); > + free(pp); > + } > + > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, > + "received an error message from QMP server: %s", > + libxl__json_object_get_string(resp)); > +} > + > +static int qmp_handle_response(libxl__qmp_handler *qmp, > + const libxl__json_object *resp) > +{ > + libxl__qmp_message_type type = LIBXL__QMP_MESSAGE_TYPE_INVALID; > + > + type = qmp_response_type(qmp, resp); > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, > + "message type: %s", libxl__qmp_message_type_to_string(type)); > + > + switch (type) { > + case LIBXL__QMP_MESSAGE_TYPE_QMP: > + /* On the greeting message from the server, enable QMP capabilities > */ > + enable_qmp_capabilities(qmp); > + break; > + case LIBXL__QMP_MESSAGE_TYPE_RETURN: { > + callback_id_pair *pp = qmp_get_callback_from_id(qmp, resp); > + > + if (pp) { > + pp->callback(qmp, > + libxl__json_map_get("return", resp, JSON_ANY)); > + if (pp->id == qmp->wait_for_id) { > + /* tell that the id have been processed */ > + qmp->wait_for_id = 0; > + } > + SIMPLEQ_REMOVE(&qmp->callback_list, pp, callback_id_pair, next); > + free(pp); > + } > + break; > + } > + case LIBXL__QMP_MESSAGE_TYPE_ERROR: > + qmp_handle_error_response(qmp, resp); > + break; > + case LIBXL__QMP_MESSAGE_TYPE_EVENT: > + break; > + case LIBXL__QMP_MESSAGE_TYPE_INVALID: > + return -1; > + } > + return 0; > +} > + > +/* > + * Handler functions > + */ > + > +static libxl__qmp_handler *qmp_init_handler(libxl_ctx *ctx, uint32_t domid) > +{ > + libxl__qmp_handler *qmp = NULL; > + > + qmp = calloc(1, sizeof (libxl__qmp_handler)); > + if (qmp == NULL) { > + LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, > + "Failed to allocate qmp_handler"); > + return NULL; > + } > + qmp->ctx = ctx; > + qmp->domid = domid; > + qmp->timeout = 5; > + > + SIMPLEQ_INIT(&qmp->callback_list); > + > + return qmp; > +} > + > +static int qmp_open(libxl__qmp_handler *qmp, const char *qmp_socket_path, > + int timeout) > +{ > + int ret; > + int i = 0; > + > + qmp->qmp_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); > + if (qmp->qmp_fd < 0) { > + return -1; > + } > + > + memset(&qmp->addr, 0, sizeof (&qmp->addr)); > + qmp->addr.sun_family = AF_UNIX; > + strncpy(qmp->addr.sun_path, qmp_socket_path, > + sizeof (qmp->addr.sun_path)); > + > + do { > + ret = connect(qmp->qmp_fd, (struct sockaddr *) &qmp->addr, > + sizeof (qmp->addr)); > + if (ret == 0) > + break; > + if (errno == ENOENT || errno == ECONNREFUSED) { > + /* ENOENT : Socket may not have shown up yet > + * ECONNREFUSED : Leftover socket hasn't been removed yet */ > + continue; > + } > + return -1; > + } while ((++i / 5 <= timeout) && (usleep(200 * 1000) <= 0)); > + > + return ret; > +} > + > +static void qmp_close(libxl__qmp_handler *qmp) > +{ > + callback_id_pair *pp = NULL; > + callback_id_pair *tmp = NULL; > + > + close(qmp->qmp_fd); > + SIMPLEQ_FOREACH(pp, &qmp->callback_list, next) { > + if (tmp) > + free(tmp); > + tmp = pp; > + } > + if (tmp) > + free(tmp); > +} > + > +static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp) > +{ > + ssize_t rd; > + char *s = NULL; > + char *s_end = NULL; > + > + char *incomplete = NULL; > + size_t incomplete_size = 0; > + > + do { > + fd_set rfds; > + int ret = 0; > + struct timeval timeout = { > + .tv_sec = qmp->timeout, > + .tv_usec = 0, > + }; > + > + FD_ZERO(&rfds); > + FD_SET(qmp->qmp_fd, &rfds); > + > + ret = select(qmp->qmp_fd + 1, &rfds, NULL, NULL, &timeout); > + if (ret == 0) { > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, "timeout"); > + return -1; > + } else if (ret < 0) { > + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, "Select error"); > + return -1; > + } > + > + rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE); > + if (rd == 0) { > + continue; > + } else if (rd < 0) { > + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, "Socket read > error"); > + return rd; > + } > + > + DEBUG_REPORT_RECEIVED(qmp->buffer, rd); > + > + do { > + char *end = NULL; > + if (incomplete) { > + size_t current_pos = s - incomplete; > + incomplete_size += rd; > + incomplete = libxl__realloc(gc, incomplete, > + incomplete_size + 1); > + incomplete = strncat(incomplete, qmp->buffer, rd); > + s = incomplete + current_pos; > + s_end = incomplete + incomplete_size; > + } else { > + incomplete = libxl__strndup(gc, qmp->buffer, rd); > + incomplete_size = rd; > + s = incomplete; > + s_end = s + rd; > + } > + > + end = strstr(s, "\r\n"); > + if (end) { > + libxl__json_object *o = NULL; > + > + *end = '\0'; > + > + o = libxl__json_parse(gc, s); > + s = end + 2; > + > + if (o) { > + qmp_handle_response(qmp, o); > + libxl__json_object_free(gc, o); > + } else { > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, > + "Parse error of : %s\n", s); > + return -1; > + } > + } else { > + break; > + } > + } while (s < s_end); > + } while (s < s_end); > + > + return 1; > +} > + > +static int qmp_send(libxl__qmp_handler *qmp, > + const char *cmd, qmp_callback_t callback) > +{ > + yajl_gen_config conf = { 0, NULL }; > + const unsigned char *buf; > + unsigned int len = 0; > + yajl_gen_status s; > + yajl_gen hand; > + > + hand = yajl_gen_alloc(&conf, NULL); > + if (!hand) { > + return -1; > + } > + > + yajl_gen_map_open(hand); > + libxl__yajl_gen_asciiz(hand, "execute"); > + libxl__yajl_gen_asciiz(hand, cmd); > + libxl__yajl_gen_asciiz(hand, "id"); > + yajl_gen_integer(hand, ++qmp->last_id_used); > + yajl_gen_map_close(hand); > + > + s = yajl_gen_get_buf(hand, &buf, &len); > + > + if (s) { > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, > + "Failed to generate a qmp command"); > + return -1; > + } > + > + if (callback) { > + callback_id_pair *elm = malloc(sizeof (callback_id_pair)); > + if (elm == NULL) { > + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, > + "Failed to allocate a QMP callback"); > + yajl_gen_free(hand); > + return -1; > + } > + elm->id = qmp->last_id_used; > + elm->callback = callback; > + SIMPLEQ_INSERT_TAIL(&qmp->callback_list, elm, next); > + } > + > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "next qmp command: '%s'", buf); > + > + if (libxl_write_exactly(qmp->ctx, qmp->qmp_fd, buf, len, > + "QMP command", "QMP socket")) > + goto error; > + if (libxl_write_exactly(qmp->ctx, qmp->qmp_fd, "\r\n", 2, > + "CRLF", "QMP socket")) > + goto error; > + > + yajl_gen_free(hand); > + > + return qmp->last_id_used; > + > +error: > + yajl_gen_free(hand); > + return -1; > +} > + > +static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, > + qmp_callback_t callback, int ask_timeout) > +{ > + int id = 0; > + int ret = 0; > + libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); > + > + id = qmp_send(qmp, cmd, callback); > + if (id <= 0) { > + return -1; > + } > + qmp->wait_for_id = id; > + > + while (qmp->wait_for_id == id) { > + if ((ret = qmp_next(&gc, qmp)) < 0) { > + return ret; > + } > + } > + > + libxl__free_all(&gc); > + > + return 0; > +} > + > +static void qmp_free_handler(libxl__qmp_handler *qmp) > +{ > + free(qmp); > +} > + > +/* > + * API > + */ > + > +libxl__qmp_handler *libxl__qmp_initialize(libxl_ctx *ctx, uint32_t domid) > +{ > + int ret = 0; > + libxl__qmp_handler *qmp = NULL; > + char *qmp_socket; > + libxl__gc gc = LIBXL_INIT_GC(ctx); > + > + qmp = qmp_init_handler(ctx, domid); > + > + qmp_socket = libxl__sprintf(&gc, "%s/qmp-libxl-%d", > + libxl_run_dir_path(), domid); > + if ((ret = qmp_open(qmp, qmp_socket, QMP_SOCKET_CONNECT_TIMEOUT)) < 0) { > + LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Connection error"); > + libxl__free_all(&gc); > + qmp_free_handler(qmp); > + return NULL; > + } > + > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "connected to %s", qmp_socket); > + > + /* Wait for the response to qmp_capabilities */ > + while (!qmp->connected) { > + if ((ret = qmp_next(&gc, qmp)) < 0) { > + break; > + } > + } > + > + libxl__free_all(&gc); > + if (!qmp->connected) { > + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to connect to QMP"); > + libxl__qmp_close(qmp); > + return NULL; > + } > + return qmp; > +} > + > +void libxl__qmp_close(libxl__qmp_handler *qmp) > +{ > + if (!qmp) > + return; > + qmp_close(qmp); > + qmp_free_handler(qmp); > +} > + > +void libxl__qmp_cleanup(libxl__gc *gc, uint32_t domid) > +{ > + libxl_ctx *ctx = libxl__gc_owner(gc); > + char *qmp_socket; > + > + qmp_socket = libxl__sprintf(gc, "%s/qmp-libxl-%d", > + libxl_run_dir_path(), domid); > + if (unlink(qmp_socket) == -1) { > + if (errno != ENOENT) { > + LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, > + "Failed to remove QMP socket file %s", > + qmp_socket); > + } > + } > +} > + > +int libxl__qmp_query_serial(libxl__qmp_handler *qmp) > +{ > + return qmp_synchronous_send(qmp, "query-chardev", > + register_serials_chardev_callback, > + qmp->timeout); > +} > + > +int libxl__qmp_initializations(libxl_ctx *ctx, uint32_t domid) > +{ > + libxl__qmp_handler *qmp = NULL; > + int ret = 0; > + > + qmp = libxl__qmp_initialize(ctx, domid); > + if (!qmp) > + return -1; > + ret = libxl__qmp_query_serial(qmp); > + libxl__qmp_close(qmp); > + return ret; > +} > -- > Anthony PERARD > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |