New: - Add a separate patch for XEN_RUN_DIR path. - Add a new patch to generate an some internal type with gentypes.py. It''s used only to have a ENUM <-> String convertion with the QMP client. - libxl_qmp.h content have been moved to libxl_internal.h - return value of every single alloc are now check - introduce some DEBUG_GEN_* macro to avoid some #ifdefs - remove unused exported function: libxL__qmp_next libxl__qmp_send_command - introduce libxl__qmp_query_serial and store all serial port chardev in xenstore. - introduce json_object_{get,is}_* inline functions. - coding style fixed Change v3->v4: - In case of a timeout, there is no more infinit loop - include select bit in the qmp_next function, to avoid have it twice in the code. - introduce libxl__qmp_cleanup to remove the socket file. It''s called from libxl_domain_destroy when a dm is present. - libxl__qmp_get_fd is removed as is not yet used. - qmp_connect renamed to qmp_open - I''m not skip anymore the CRLF a the end of a command. So there will always be another turn in the loop to eat them. - fix coding style issue related to struct definitions. - the receive buffer is now include in the qmp_handler struct to avoid an extra alloc. - in struct json_object, rename floating to fp. - introduce yajl_gen_asciiz that take a string nul-terminated and give it to yajl_gen_string. - use "-chardev ... -mon ..." qemu option instead of -qmp "..." Change v2->v3: - Use of a timeout when wait for a reply from the server. - Use of a command list, a list of pair "command" + callback. It''s associated with an enum. - Introduce libxl__qmp_initializations that will ask of all informations need through QMP. (It''s just a rename of libxl__qmp_get_serial_console_path from the previous patch.) Change v1->v2: - Introduction of libxl_run_dir_path(), should maybe be in another patch. - Add a new static function qmp_synchronous_send that wait the answer from the server. - QMP is know use only inside libxl, so only one command is send through the socket and after, the connection is closed. Anthony PERARD (3): Introduce XEN_RUN_DIR path. libxl: Introduce libxl_internal_types.idl. libxl, Introduce a QMP client Config.mk | 1 + config/StdGNU.mk | 2 + tools/libxl/Makefile | 14 +- tools/libxl/gentypes.py | 15 +- tools/libxl/libxl.c | 2 + tools/libxl/libxl.h | 1 + tools/libxl/libxl_create.c | 3 + tools/libxl/libxl_dm.c | 9 + tools/libxl/libxl_internal.h | 19 + tools/libxl/libxl_internal_types.idl | 10 + tools/libxl/libxl_paths.c | 5 + tools/libxl/libxl_qmp.c | 1116 ++++++++++++++++++++++++++++++++++ 12 files changed, 1189 insertions(+), 8 deletions(-) create mode 100644 tools/libxl/libxl_internal_types.idl create mode 100644 tools/libxl/libxl_qmp.c -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-27 15:12 UTC
[Xen-devel] [PATCH V5 1/3] Introduce XEN_RUN_DIR path.
This patch also add libxl_run_dir_path() function in libxl. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- Config.mk | 1 + config/StdGNU.mk | 2 ++ tools/libxl/Makefile | 1 + tools/libxl/libxl.h | 1 + tools/libxl/libxl_paths.c | 5 +++++ 5 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Config.mk b/Config.mk index aa681ae..72fc729 100644 --- a/Config.mk +++ b/Config.mk @@ -133,6 +133,7 @@ define buildmakevars2file-closure echo "XEN_CONFIG_DIR=\"$(XEN_CONFIG_DIR)\"" >> $(1).tmp; \ echo "XEN_SCRIPT_DIR=\"$(XEN_SCRIPT_DIR)\"" >> $(1).tmp; \ echo "XEN_LOCK_DIR=\"$(XEN_LOCK_DIR)\"" >> $(1).tmp; \ + echo "XEN_RUN_DIR=\"$(XEN_RUN_DIR)\"" >> $(1).tmp; \ if ! cmp $(1).tmp $(1); then mv -f $(1).tmp $(1); fi endef diff --git a/config/StdGNU.mk b/config/StdGNU.mk index 25aeb4d..68fa226 100644 --- a/config/StdGNU.mk +++ b/config/StdGNU.mk @@ -52,9 +52,11 @@ PRIVATE_BINDIR = $(PRIVATE_PREFIX)/bin ifeq ($(PREFIX),/usr) CONFIG_DIR = /etc XEN_LOCK_DIR = /var/lock +XEN_RUN_DIR = /var/run/xen else CONFIG_DIR = $(PREFIX)/etc XEN_LOCK_DIR = $(PREFIX)/var/lock +XEN_RUN_DIR = $(PREFIX)/var/run/xen endif SYSCONFIG_DIR = $(CONFIG_DIR)/$(CONFIG_LEAF_DIR) diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index 77724b3..bfe9c58 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -123,6 +123,7 @@ install: all $(INSTALL_DIR) $(DESTDIR)$(LIBDIR) $(INSTALL_DIR) $(DESTDIR)$(INCLUDEDIR) $(INSTALL_DIR) $(DESTDIR)$(BASH_COMPLETION_DIR) + $(INSTALL_DIR) $(DESTDIR)$(XEN_RUN_DIR) $(INSTALL_PROG) xl $(DESTDIR)$(SBINDIR) $(INSTALL_PROG) libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR) ln -sf libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libxenlight.so.$(MAJOR) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index b8392b7..da878e4 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -529,6 +529,7 @@ const char *libxl_xenfirmwaredir_path(void); const char *libxl_xen_config_dir_path(void); const char *libxl_xen_script_dir_path(void); const char *libxl_lock_dir_path(void); +const char *libxl_run_dir_path(void); #endif /* LIBXL_H */ diff --git a/tools/libxl/libxl_paths.c b/tools/libxl/libxl_paths.c index 9c2bd06..192501f 100644 --- a/tools/libxl/libxl_paths.c +++ b/tools/libxl/libxl_paths.c @@ -64,3 +64,8 @@ const char *libxl_lock_dir_path(void) { return XEN_LOCK_DIR; } + +const char *libxl_run_dir_path(void) +{ + return XEN_RUN_DIR; +} -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-27 15:12 UTC
[Xen-devel] [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- tools/libxl/Makefile | 10 +++++++++- tools/libxl/gentypes.py | 15 ++++++++------- tools/libxl/libxl_internal.h | 1 + tools/libxl/libxl_internal_types.idl | 10 ++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 tools/libxl/libxl_internal_types.idl diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index bfe9c58..f148ad3 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -35,7 +35,7 @@ LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o 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_OBJS-y) -LIBXL_OBJS += _libxl_types.o libxl_flask.o +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_internal_types.o $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) @@ -79,14 +79,22 @@ _libxl_paths.h: genpath libxl_paths.c: _libxl_paths.h libxl.h: _libxl_types.h +libxl_internal.h: _libxl_internal_types.h $(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h +$(LIBXL_OBJS): libxl_internal.h _libxl_%.h _libxl_%.c: libxl.idl gen%.py libxl%.py $(PYTHON) gen$*.py libxl.idl __libxl_$*.h __libxl_$*.c mv __libxl_$*.h _libxl_$*.h mv __libxl_$*.c _libxl_$*.c +.NOTPARALLEL: _libxl_internal_types.h _libxl_internal_types.c +_libxl_internal_types.h _libxl_internal_types.c: libxl_internal_types.idl gentypes.py libxltypes.py + $(PYTHON) gentypes.py $< __libxl_internal_types.h __libxl_internal_types.c + mv __libxl_internal_types.h _libxl_internal_types.h + mv __libxl_internal_types.c _libxl_internal_types.c + libxenlight.so: libxenlight.so.$(MAJOR) ln -sf $< $@ diff --git a/tools/libxl/gentypes.py b/tools/libxl/gentypes.py index c9a3d9c..5188b66 100644 --- a/tools/libxl/gentypes.py +++ b/tools/libxl/gentypes.py @@ -162,9 +162,10 @@ if __name__ == ''__main__'': print "outputting libxl type definitions to %s" % header f = open(header, "w") - - f.write("""#ifndef __LIBXL_TYPES_H -#define __LIBXL_TYPES_H + + header_define = header.upper().replace(''.'',''_'') + f.write("""#ifndef %s +#define %s /* * DO NOT EDIT. @@ -172,9 +173,9 @@ if __name__ == ''__main__'': * This file is autogenerated by * "%s" */ - -""" % " ".join(sys.argv)) - + +""" % (header_define, header_define, " ".join(sys.argv))) + for ty in types: f.write(libxl_C_type_define(ty) + ";\n") if ty.destructor_fn is not None: @@ -185,7 +186,7 @@ if __name__ == ''__main__'': f.write("extern libxl_enum_string_table %s_string_table[];\n" % (ty.typename)) f.write("\n") - f.write("""#endif /* __LIBXL_TYPES_H */\n""") + f.write("""#endif /* %s */\n""" % (header_define)) f.close() impl = sys.argv[3] diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 297310d..af35861 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -35,6 +35,7 @@ #include "flexarray.h" #include "libxl_utils.h" +#include "_libxl_internal_types.h" #define LIBXL_DESTROY_TIMEOUT 10 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10 diff --git a/tools/libxl/libxl_internal_types.idl b/tools/libxl/libxl_internal_types.idl new file mode 100644 index 0000000..d993298 --- /dev/null +++ b/tools/libxl/libxl_internal_types.idl @@ -0,0 +1,10 @@ + +libxl__qmp_message_type = Enumeration("qmp_message_type", [ + (1, "QMP"), + (2, "return"), + (3, "error"), + (4, "event"), + (5, "invalid"), + ], + namespace = "libxl__") + -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-27 15:12 UTC
[Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
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 serial0 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-$(domid). Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- tools/libxl/Makefile | 3 + tools/libxl/libxl.c | 2 + tools/libxl/libxl_create.c | 3 + tools/libxl/libxl_dm.c | 9 + tools/libxl/libxl_internal.h | 18 + tools/libxl/libxl_qmp.c | 1116 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1151 insertions(+), 0 deletions(-) create mode 100644 tools/libxl/libxl_qmp.c diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index f148ad3..86ba7b0 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -32,6 +32,9 @@ endif LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o +LIBXL_OBJS-y += libxl_qmp.o +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_OBJS-y) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index c21cfe7..e09d7a7 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -757,6 +757,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 08d6539..06a4e42 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -522,6 +522,9 @@ 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 76d72a5..fa11370 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -249,6 +249,15 @@ 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-%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 af35861..d91cee4 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -379,4 +379,22 @@ _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); + #endif diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c new file mode 100644 index 0000000..6b1fdc6 --- /dev/null +++ b/tools/libxl/libxl_qmp.c @@ -0,0 +1,1116 @@ +/* + * Copyright (C) 2011 Citrix Ltd. + * Author Anthony PERARD <anthony.perard@citrix.com> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/un.h> +#include <sys/queue.h> + +#include <yajl/yajl_parse.h> +#include <yajl/yajl_gen.h> + +#include "libxl_internal.h" +#include "flexarray.h" + +/* #define DEBUG_ANSWER */ +/* #define DEBUG_RECEIVED */ + +#ifdef DEBUG_ANSWER +# define DEBUG_GEN(h, type) yajl_gen_##type(h) +# define DEBUG_GEN_VALUE(h, type, value) yajl_gen_##type(h, value) +# define DEBUG_GEN_STRING(h, str, n) yajl_gen_string(h, str, n) +#else +# define DEBUG_GEN(h, type) (void)0 +# define DEBUG_GEN_VALUE(h, type, value) (void)0 +# define DEBUG_GEN_STRING(h, value, lenght) (void)0 +#endif + +/* + * json_object types + */ + +typedef enum { + JSON_ERROR, + JSON_NULL, + JSON_TRUE, + JSON_FALSE, + JSON_INTEGER, + JSON_DOUBLE, + JSON_STRING, + JSON_MAP, + JSON_ARRAY, + JSON_ANY +} node_type; + +typedef struct json_object { + node_type type; + union { + long i; + double d; + const char *string; + /* List of json_object */ + flexarray_t *array; + /* List of json_map_node */ + flexarray_t *map; + } u; + struct json_object *parent; +} json_object; + +typedef struct { + const char *map_key; + json_object *obj; +} json_map_node; + +/* + * QMP types & constant + */ + +#define QMP_RECEIVE_BUFFER_SIZE 4096 + +typedef int (*qmp_callback_t)(libxl__qmp_handler *qmp, + const 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; + + unsigned char buffer[QMP_RECEIVE_BUFFER_SIZE]; + yajl_handle hand; + + json_object *head; + json_object *current; + + libxl_ctx *ctx; + uint32_t domid; + + int last_id_used; + SIMPLEQ_HEAD(callback_list, callback_id_pair) callback_list; +#ifdef DEBUG_ANSWER + yajl_gen g; +#endif +}; + +static int qmp_send(libxl__qmp_handler *qmp, + const char *cmd, qmp_callback_t callback); + +static const int QMP_SOCKET_CONNECT_TIMEOUT = 5; + +/* + * json_object helper functions + */ + +static inline bool json_object_is_string(const json_object *o) +{ + return o != NULL && o->type == JSON_STRING; +} + +static inline bool json_object_is_integer(const json_object *o) +{ + return o != NULL && o->type == JSON_INTEGER; +} + +static inline bool json_object_is_map(const json_object *o) +{ + return o != NULL && o->type == JSON_MAP; +} + +static inline bool json_object_is_array(const json_object *o) +{ + return o != NULL && o->type == JSON_ARRAY; +} + + +static inline const char *json_object_get_string(const json_object *o) +{ + if (json_object_is_string(o)) + return o->u.string; + else + return NULL; +} + +static inline flexarray_t *json_object_get_map(const json_object *o) +{ + if (json_object_is_map(o)) + return o->u.map; + else + return NULL; +} + +static inline flexarray_t *json_object_get_array(const json_object *o) +{ + if (json_object_is_array(o)) + return o->u.array; + else + return NULL; +} + +static inline long json_object_get_integer(const json_object *o) +{ + if (json_object_is_integer(o)) + return o->u.i; + else + return -1; +} + + +static json_object *json_object_alloc(libxl__qmp_handler *qmp, + node_type type) +{ + json_object *obj; + + obj = calloc(1, sizeof (json_object)); + if (obj == NULL) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Failed to allocate a json_object"); + return NULL; + } + + obj->type = type; + + if (type == JSON_MAP || type == JSON_ARRAY) { + flexarray_t *array = flexarray_make(1, 1); + if (array == NULL) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Failed to allocate a flexarray"); + free(obj); + return NULL; + } + if (type == JSON_MAP) + obj->u.map = array; + else + obj->u.array = array; + } + + return obj; +} + +static int json_object_append_to(libxl__qmp_handler *qmp, + json_object *obj, json_object *dst) +{ + if (!dst) { + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "No parent json object to fill"); + return -1; + } + + switch (dst->type) { + case JSON_MAP: { + json_map_node *last; + + if (dst->u.map->count == 0) { + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "Try to add a value to an empty map (with no key)"); + return -1; + } + flexarray_get(dst->u.map, dst->u.map->count - 1, (void**)&last); + last->obj = obj; + break; + } + case JSON_ARRAY: + if (flexarray_append(dst->u.array, obj) == 2) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Failed to grow a flexarray"); + return -1; + } + break; + default: + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "Try append an object is not a map/array (%i)\n", + dst->type); + return -1; + } + + obj->parent = dst; + return 0; +} + +static void json_object_free(libxl__qmp_handler *qmp, json_object *obj) +{ + int index = 0; + + if (obj == NULL) + return; + switch (obj->type) { + case JSON_STRING: + free((void*)obj->u.string); + break; + case JSON_MAP: { + json_map_node *node = NULL; + + for (index = 0; index < obj->u.map->count; index++) { + if (flexarray_get(obj->u.map, index, (void**)&node) != 0) + break; + json_object_free(qmp, node->obj); + free((void*)node->map_key); + free(node); + node = NULL; + } + flexarray_free(obj->u.map); + break; + } + case JSON_ARRAY: { + json_object *node = NULL; + break; + + for (index = 0; index < obj->u.array->count; index++) { + if (flexarray_get(obj->u.array, index, (void**)&node) != 0) + break; + json_object_free(qmp, node); + node = NULL; + } + flexarray_free(obj->u.array); + break; + } + default: + break; + } + free(obj); +} + +static const json_object *json_object_get(const char *key, + const json_object *o, + node_type expected_type) +{ + flexarray_t *maps = NULL; + int index = 0; + + if (json_object_is_map(o)) { + json_map_node *node = NULL; + + maps = o->u.map; + for (index = 0; index < maps->count; index++) { + if (flexarray_get(maps, index, (void**)&node) != 0) + return NULL; + if (strcmp(key, node->map_key) == 0) { + if (expected_type == JSON_ANY + || (node->obj && node->obj->type == expected_type)) { + return node->obj; + } else { + return NULL; + } + } + } + } + return NULL; +} + +/* + * JSON callbacks + */ + +static int json_callback_null(void *opaque) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj; + + DEBUG_GEN(qmp->g, null); + + if ((obj = json_object_alloc(qmp, JSON_NULL)) == NULL) + return 0; + + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + + return 1; +} + +static int json_callback_boolean(void *opaque, int boolean) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj; + + DEBUG_GEN_VALUE(qmp->g, bool, boolean); + + if ((obj = json_object_alloc(qmp, + boolean ? JSON_TRUE : JSON_FALSE)) == NULL) + return 0; + + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + + return 1; +} + +static int json_callback_integer(void *opaque, long value) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj; + + DEBUG_GEN_VALUE(qmp->g, integer, value); + + if ((obj = json_object_alloc(qmp, JSON_INTEGER)) == NULL) + return 0; + obj->u.i = value; + + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + + return 1; +} + +static int json_callback_double(void *opaque, double value) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj; + + DEBUG_GEN_VALUE(qmp->g, double, value); + + if ((obj = json_object_alloc(qmp, JSON_DOUBLE)) == NULL) + return 0; + obj->u.d = value; + + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + + return 1; +} + +static int json_callback_string(void *opaque, const unsigned char *str, + unsigned int len) +{ + libxl__qmp_handler *qmp = opaque; + char *t = malloc(len + 1); + json_object *obj = NULL; + + if (t == NULL) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, "Failed to allocate"); + return 0; + } + + DEBUG_GEN_STRING(qmp->g, str, len); + + strncpy(t, (const char *) str, len); + t[len] = 0; + + if ((obj = json_object_alloc(qmp, JSON_STRING)) == NULL) { + free(t); + return 0; + } + obj->u.string = t; + + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + + return 1; +} + +static int json_callback_map_key(void *opaque, const unsigned char *str, + unsigned int len) +{ + libxl__qmp_handler *qmp = opaque; + char *t = malloc(len + 1); + json_object *obj = qmp->current; + + if (t == NULL) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, "Failed to allocate"); + return 0; + } + + DEBUG_GEN_STRING(qmp->g, str, len); + + strncpy(t, (const char *) str, len); + t[len] = 0; + + if (json_object_is_map(obj)) { + json_map_node *node = malloc(sizeof (json_map_node)); + if (node == NULL) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Failed to allocate"); + return 0; + } + + node->map_key = t; + node->obj = NULL; + + if (flexarray_append(obj->u.map, node) == 2) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Failed to grow a flexarray"); + return 0; + } + } else { + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "Current json object is not a map"); + return 0; + } + + return 1; +} + +static int json_callback_start_map(void *opaque) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj = NULL; + + DEBUG_GEN(qmp->g, map_open); + + if ((obj = json_object_alloc(qmp, JSON_MAP)) == NULL) + return 0; + + if (qmp->current) { + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + } + + qmp->current = obj; + if (qmp->head == NULL) { + qmp->head = obj; + } + + return 1; +} + +static int json_callback_end_map(void *opaque) +{ + libxl__qmp_handler *qmp = opaque; + + DEBUG_GEN(qmp->g, map_close); + + if (qmp->current) { + qmp->current = qmp->current->parent; + } else { + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "No current json_object, cannot use his parent."); + return 0; + } + + return 1; +} + +static int json_callback_start_array(void *opaque) +{ + libxl__qmp_handler *qmp = opaque; + json_object *obj = NULL; + + DEBUG_GEN(qmp->g, array_open); + + if ((obj = json_object_alloc(qmp, JSON_ARRAY)) == NULL) + return 0; + + if (qmp->current) { + if (json_object_append_to(qmp, obj, qmp->current) == -1) { + json_object_free(qmp, obj); + return 0; + } + } + + qmp->current = obj; + if (qmp->head == NULL) { + qmp->head = obj; + } + + return 1; +} + +static int json_callback_end_array(void *opaque) +{ + libxl__qmp_handler *qmp = opaque; + + DEBUG_GEN(qmp->g, array_close); + + if (qmp->current) { + qmp->current = qmp->current->parent; + } else { + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, + "No current json_object, cannot use his parent."); + return 0; + } + + return 1; +} + +static yajl_callbacks callbacks = { + json_callback_null, + json_callback_boolean, + json_callback_integer, + json_callback_double, + NULL, + json_callback_string, + json_callback_start_map, + json_callback_map_key, + json_callback_end_map, + json_callback_start_array, + json_callback_end_array +}; + +/* + * 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 json_object *o) +{ + const json_object *obj = NULL; + const json_object *label = NULL; + const char *s = NULL; + flexarray_t *array = NULL; + int index = 0; + const char *chardev = NULL; + int ret = 0; + + if ((array = json_object_get_array(o)) == NULL) { + return -1; + } + + for (index = 0; index < array->count; index++) { + if (flexarray_get(array, index, (void**)&obj) != 0) + break; + label = json_object_get("label", obj, JSON_STRING); + s = json_object_get_string(label); + + if (s && strncmp("serial", s, strlen("serial")) == 0) { + const json_object *filename = NULL; + char *endptr = NULL; + int port_number; + + filename = json_object_get("filename", obj, JSON_STRING); + chardev = 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 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 json_object *o) +{ + flexarray_t *maps = json_object_get_map(o); + libxl__qmp_message_type type; + + if (maps) { + json_map_node *node = NULL; + int index = 0; + + for (index = 0; index < maps->count; index++) { + if (flexarray_get(maps, index, (void**)&node) != 0) + break; + 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 json_object *o) +{ + const json_object *id_object = json_object_get("id", o, JSON_INTEGER); + int id = -1; + callback_id_pair *pp = NULL; + + if (id_object) { + id = 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 json_object *resp) +{ + callback_id_pair *pp = qmp_get_callback_from_id(qmp, resp); + + resp = json_object_get("error", resp, JSON_MAP); + resp = json_object_get("desc", resp, JSON_STRING); + + if (pp) { + 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", + json_object_get_string(resp)); +} + +static int qmp_handle_response(libxl__qmp_handler *qmp, + const 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, json_object_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; +} + +static inline yajl_gen_status yajl_gen_asciiz(yajl_gen hand, const char *str) +{ + return yajl_gen_string(hand, (const unsigned char *)str, strlen(str)); +} + +/* + * 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; +#ifdef DEBUG_ANSWER + if (qmp->g) + yajl_gen_free(qmp->g); +#endif + if (qmp->hand) + yajl_free(qmp->hand); + 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__qmp_handler *qmp) +{ + yajl_status status; + ssize_t rd; + ssize_t bytes_parsed = 0; + + /* read the socket */ + while (1) { + 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) { + rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE); + if (rd > 0) { + break; + } else if (rd < 0) { + LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, + "Socket read error"); + return rd; + } + } else 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; + } + } +#ifdef DEBUG_RECEIVED + qmp->buffer[rd] = 0; + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "received: ''%s''", qmp->buffer); +#endif + + while (bytes_parsed < rd) { +#ifdef DEBUG_ANSWER + if (qmp->g == NULL) { + yajl_gen_config conf = { 1, " " }; + qmp->g = yajl_gen_alloc(&conf, NULL); + } +#endif + /* parse the input */ + if (qmp->hand == NULL) { + /* allow comments */ + yajl_parser_config cfg = { 1, 1 }; + qmp->hand = yajl_alloc(&callbacks, &cfg, NULL, qmp); + } + status = yajl_parse(qmp->hand, + qmp->buffer + bytes_parsed, rd - bytes_parsed); + bytes_parsed += yajl_get_bytes_consumed(qmp->hand); + + /* handle the answer */ + if (status != yajl_status_ok + && status != yajl_status_insufficient_data) { + unsigned char *str = yajl_get_error(qmp->hand, + 1, qmp->buffer, rd); + + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, "yajl error: %s", str); + yajl_free_error(qmp->hand, str); + return -1; + } + + if (status == yajl_status_ok) { +#ifdef DEBUG_ANSWER + const unsigned char *buf = NULL; + unsigned int len = 0; + + yajl_gen_get_buf(qmp->g, &buf, &len); + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "response:\n%s", buf); + yajl_gen_free(qmp->g); + qmp->g = NULL; +#endif + + qmp_handle_response(qmp, qmp->head); + + json_object_free(qmp, qmp->head); + qmp->head = NULL; + qmp->current = NULL; + + yajl_free(qmp->hand); + qmp->hand = NULL; + } + /* skip the CRLF of the end of a command, this avoid doing an extra + * turn just for them */ + while (bytes_parsed < rd && (qmp->buffer[bytes_parsed] == ''\r'' + || qmp->buffer[bytes_parsed] == ''\n'')) { + bytes_parsed++; + } + } + 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); + yajl_gen_asciiz(hand, "execute"); + yajl_gen_asciiz(hand, cmd); + 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; + + 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(qmp)) < 0) { + return ret; + } + } + + 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-%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"); + 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(qmp)) < 0) { + break; + } + } + + libxl__free_all(&gc); + 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-%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; + if (qmp->connected) { + ret = libxl__qmp_query_serial(qmp); + } + libxl__qmp_close(qmp); + return ret; +} -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Jun-27 15:20 UTC
[Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
On Mon, 2011-06-27 at 16:12 +0100, Anthony PERARD wrote:> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > --- > tools/libxl/Makefile | 10 +++++++++- > tools/libxl/gentypes.py | 15 ++++++++------- > tools/libxl/libxl_internal.h | 1 + > tools/libxl/libxl_internal_types.idl | 10 ++++++++++Do you not need to update .hgignore?> 4 files changed, 28 insertions(+), 8 deletions(-) > create mode 100644 tools/libxl/libxl_internal_types.idl > > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > index bfe9c58..f148ad3 100644 > --- a/tools/libxl/Makefile > +++ b/tools/libxl/Makefile > @@ -35,7 +35,7 @@ LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o > 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_OBJS-y) > -LIBXL_OBJS += _libxl_types.o libxl_flask.o > +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_internal_types.o > > $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) > > @@ -79,14 +79,22 @@ _libxl_paths.h: genpath > libxl_paths.c: _libxl_paths.h > > libxl.h: _libxl_types.h > +libxl_internal.h: _libxl_internal_types.h > > $(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h > +$(LIBXL_OBJS): libxl_internal.h > > _libxl_%.h _libxl_%.c: libxl.idl gen%.py libxl%.py > $(PYTHON) gen$*.py libxl.idl __libxl_$*.h __libxl_$*.cIf you simply s/gen$*.py/gentypes.py/ and s/libxl.idl/libxl$*.idl/g and leave the other patterns does this rule work for both IDL files?> mv __libxl_$*.h _libxl_$*.h > mv __libxl_$*.c _libxl_$*.c > > +.NOTPARALLEL: _libxl_internal_types.h _libxl_internal_types.cI''d been wondering how to do that!> +_libxl_internal_types.h _libxl_internal_types.c: libxl_internal_types.idl gentypes.py libxltypes.py > + $(PYTHON) gentypes.py $< __libxl_internal_types.h __libxl_internal_types.c > + mv __libxl_internal_types.h _libxl_internal_types.h > + mv __libxl_internal_types.c _libxl_internal_types.c > + > libxenlight.so: libxenlight.so.$(MAJOR) > ln -sf $< $@ > > diff --git a/tools/libxl/gentypes.py b/tools/libxl/gentypes.py > index c9a3d9c..5188b66 100644 > --- a/tools/libxl/gentypes.py > +++ b/tools/libxl/gentypes.py > @@ -162,9 +162,10 @@ if __name__ == ''__main__'': > print "outputting libxl type definitions to %s" % header > > f = open(header, "w") > - > - f.write("""#ifndef __LIBXL_TYPES_H > -#define __LIBXL_TYPES_H > + > + header_define = header.upper().replace(''.'',''_'') > + f.write("""#ifndef %s > +#define %s > > /* > * DO NOT EDIT. > @@ -172,9 +173,9 @@ if __name__ == ''__main__'': > * This file is autogenerated by > * "%s" > */ > - > -""" % " ".join(sys.argv)) > - > + > +""" % (header_define, header_define, " ".join(sys.argv))) > + > for ty in types: > f.write(libxl_C_type_define(ty) + ";\n") > if ty.destructor_fn is not None: > @@ -185,7 +186,7 @@ if __name__ == ''__main__'': > f.write("extern libxl_enum_string_table %s_string_table[];\n" % (ty.typename)) > f.write("\n") > > - f.write("""#endif /* __LIBXL_TYPES_H */\n""") > + f.write("""#endif /* %s */\n""" % (header_define)) > f.close() > > impl = sys.argv[3] > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index 297310d..af35861 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -35,6 +35,7 @@ > > #include "flexarray.h" > #include "libxl_utils.h" > +#include "_libxl_internal_types.h" > > #define LIBXL_DESTROY_TIMEOUT 10 > #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10 > diff --git a/tools/libxl/libxl_internal_types.idl b/tools/libxl/libxl_internal_types.idl > new file mode 100644 > index 0000000..d993298 > --- /dev/null > +++ b/tools/libxl/libxl_internal_types.idl > @@ -0,0 +1,10 @@ > + > +libxl__qmp_message_type = Enumeration("qmp_message_type", [ > + (1, "QMP"), > + (2, "return"), > + (3, "error"), > + (4, "event"), > + (5, "invalid"), > + ], > + namespace = "libxl__") > +_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-27 15:40 UTC
Re: [Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
On Mon, Jun 27, 2011 at 16:20, Ian Campbell <Ian.Campbell@eu.citrix.com> wrote:> On Mon, 2011-06-27 at 16:12 +0100, Anthony PERARD wrote: >> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> >> --- >> tools/libxl/Makefile | 10 +++++++++- >> tools/libxl/gentypes.py | 15 ++++++++------- >> tools/libxl/libxl_internal.h | 1 + >> tools/libxl/libxl_internal_types.idl | 10 ++++++++++ > > Do you not need to update .hgignore?I don''t use mercurial! :) But no, the file generated will be catch by: ^tools/libxl/_.*\.h$>> 4 files changed, 28 insertions(+), 8 deletions(-) >> create mode 100644 tools/libxl/libxl_internal_types.idl >> >> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile >> index bfe9c58..f148ad3 100644 >> --- a/tools/libxl/Makefile >> +++ b/tools/libxl/Makefile >> @@ -35,7 +35,7 @@ LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o >> 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_OBJS-y) >> -LIBXL_OBJS += _libxl_types.o libxl_flask.o >> +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_internal_types.o >> >> $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) >> >> @@ -79,14 +79,22 @@ _libxl_paths.h: genpath >> libxl_paths.c: _libxl_paths.h >> >> libxl.h: _libxl_types.h >> +libxl_internal.h: _libxl_internal_types.h >> >> $(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h >> +$(LIBXL_OBJS): libxl_internal.h >> >> _libxl_%.h _libxl_%.c: libxl.idl gen%.py libxl%.py >> $(PYTHON) gen$*.py libxl.idl __libxl_$*.h __libxl_$*.c > > If you simply s/gen$*.py/gentypes.py/ and s/libxl.idl/libxl$*.idl/g and > leave the other patterns does this rule work for both IDL files?Yes, it''s works, with a `mv libxl.idl libxl_types.idl`. I thought this rules was used by something else.>> mv __libxl_$*.h _libxl_$*.h >> mv __libxl_$*.c _libxl_$*.c >> >> +.NOTPARALLEL: _libxl_internal_types.h _libxl_internal_types.c > > I''d been wondering how to do that!Better than a -j1, first time I use it but seams to work fine. -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jun-27 16:07 UTC
Re: [Xen-devel] [PATCH V5 1/3] Introduce XEN_RUN_DIR path.
Anthony PERARD writes ("[Xen-devel] [PATCH V5 1/3] Introduce XEN_RUN_DIR path."):> This patch also add libxl_run_dir_path() function in libxl.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com> _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jun-27 16:17 UTC
Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
Anthony PERARD writes ("[Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client"):> 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 serial0 in xenstored. So we will be able to use xl console with > QEMU upstream.Can I make a suggestion ? I think the formulaic json parser stuff could usefully live in a separate file.> +static inline yajl_gen_status yajl_gen_asciiz(yajl_gen hand, constchar *str) Isn''t this a hostage to fortune ? yajl may grow an identically-named function in which case this will no longer build.> +#ifdef DEBUG_ANSWER > + if (qmp->g) > + yajl_gen_free(qmp->g); > +#endifCan this #ifdef not be shuffled off somewhere ? Ie, make a debug function (or macro) which we call unconditionally. The rest looks plausible. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-27 17:04 UTC
Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
On Mon, Jun 27, 2011 at 17:17, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote:> Anthony PERARD writes ("[Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client"): >> 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 serial0 in xenstored. So we will be able to use xl console with >> QEMU upstream. > > Can I make a suggestion ? I think the formulaic json parser stuff > could usefully live in a separate file.Ok, I will cut the file.>> +static inline yajl_gen_status yajl_gen_asciiz(yajl_gen hand, const > char *str) > > Isn''t this a hostage to fortune ? yajl may grow an identically-named > function in which case this will no longer build.Maybe. I will rename to libxl__yajl_gen_asciiz.>> +#ifdef DEBUG_ANSWER >> + if (qmp->g) >> + yajl_gen_free(qmp->g); >> +#endif > > Can this #ifdef not be shuffled off somewhere ? Ie, make a debug > function (or macro) which we call unconditionally.Ok, I will remove all the #ifdef debug_answer.> The rest looks plausible.Thanks for the review, -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Jun-28 08:57 UTC
Re: [Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
On Mon, 2011-06-27 at 16:40 +0100, Anthony PERARD wrote:> On Mon, Jun 27, 2011 at 16:20, Ian Campbell <Ian.Campbell@eu.citrix.com> wrote: > > On Mon, 2011-06-27 at 16:12 +0100, Anthony PERARD wrote: > >> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > >> --- > >> tools/libxl/Makefile | 10 +++++++++- > >> tools/libxl/gentypes.py | 15 ++++++++------- > >> tools/libxl/libxl_internal.h | 1 + > >> tools/libxl/libxl_internal_types.idl | 10 ++++++++++ > > > > Do you not need to update .hgignore? > > I don''t use mercurial! :) > But no, the file generated will be catch by: > ^tools/libxl/_.*\.h$ > > >> 4 files changed, 28 insertions(+), 8 deletions(-) > >> create mode 100644 tools/libxl/libxl_internal_types.idl > >> > >> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > >> index bfe9c58..f148ad3 100644 > >> --- a/tools/libxl/Makefile > >> +++ b/tools/libxl/Makefile > >> @@ -35,7 +35,7 @@ LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o > >> 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_OBJS-y) > >> -LIBXL_OBJS += _libxl_types.o libxl_flask.o > >> +LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_internal_types.o > >> > >> $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) > >> > >> @@ -79,14 +79,22 @@ _libxl_paths.h: genpath > >> libxl_paths.c: _libxl_paths.h > >> > >> libxl.h: _libxl_types.h > >> +libxl_internal.h: _libxl_internal_types.h > >> > >> $(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h > >> +$(LIBXL_OBJS): libxl_internal.h > >> > >> _libxl_%.h _libxl_%.c: libxl.idl gen%.py libxl%.py > >> $(PYTHON) gen$*.py libxl.idl __libxl_$*.h __libxl_$*.c > > > > If you simply s/gen$*.py/gentypes.py/ and s/libxl.idl/libxl$*.idl/g and > > leave the other patterns does this rule work for both IDL files? > > Yes, it''s works, with a `mv libxl.idl libxl_types.idl`.Can you incorporate the _types into the rule itself or does make not allow for % to match zero-characters?> I thought this rules was used by something else.No it''s just used once. The reason it is currently a pattern rule is to work around make which will run a rule with multiple targets multiple times _unless_ it is a pattern rule. e.g. A B: C DO SOMETHING will "DO SOMETHING" twice, rather than once. Using a pattern rule is something of a hack. Another option might be to artificially split the multi pattern rule, e.g. do something like _libxl_xxx.c: _libxl_xxx.h _libxl_xxx.h: libxl.idl etc etc genwrap.py ... etc etc mv ... At first I thought the better way was your use of .NOTPARALLEL but actually it is probably still running the rule multiple times for no reason and you have just worked around the problem with multiple parallel invocations of the mv''s.> > >> mv __libxl_$*.h _libxl_$*.h > >> mv __libxl_$*.c _libxl_$*.c > >> > >> +.NOTPARALLEL: _libxl_internal_types.h _libxl_internal_types.c > > > > I''d been wondering how to do that! > > Better than a -j1, first time I use it but seams to work fine. >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Jun-28 09:14 UTC
Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
On Mon, 2011-06-27 at 18:04 +0100, Anthony PERARD wrote:> On Mon, Jun 27, 2011 at 17:17, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote: > > Anthony PERARD writes ("[Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client"): > >> 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 serial0 in xenstored. So we will be able to use xl console with > >> QEMU upstream. > > > > Can I make a suggestion ? I think the formulaic json parser stuff > > could usefully live in a separate file. > > Ok, I will cut the file.FWIW my "libxl: IDL: autogenerate functions to produce JSON from libxl data structures" patch added libxl_json.c. If you want to add that file with the bits you need I will rebase onto it (since I need to rework at least this last patch of my series anyway, see below).> >> +static inline yajl_gen_status yajl_gen_asciiz(yajl_gen hand, const > > char *str) > > > > Isn''t this a hostage to fortune ? yajl may grow an identically-named > > function in which case this will no longer build. > > Maybe. I will rename to libxl__yajl_gen_asciiz.Good idea. My patch also added yajl_gen_asciiz. I shall defer to the version which you will have added when I rebase.> >> +#ifdef DEBUG_ANSWER > >> + if (qmp->g) > >> + yajl_gen_free(qmp->g); > >> +#endif > > > > Can this #ifdef not be shuffled off somewhere ? Ie, make a debug > > function (or macro) which we call unconditionally. > > Ok, I will remove all the #ifdef debug_answer.I think Ian was only suggesting to remove the ifdef''s from the main flow of code and you''ve done that for most of the uses with your DEBUG_GEN* but here perhaps you could also define and call functions which are empty in the non-debug case. e.g. DEBUG_GEN_START, DEBUG_GEN_END, DEBUG_GEN_REPORT? BTW I noticed: +#ifdef DEBUG_RECEIVED + qmp->buffer[rd] = 0; + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "received: ''%s''", qmp->buffer); +#endif I wondered if the zero termination of the string should be there even in the non-debug case? Also is there a buffer overrun (when rd==QMP_RECEIVE_BUFFER_SIZE)? If its the latter you could perhaps use printf("%*s", rd, qmp->buf); ? Having done that then: #define DEBUG_RECEIVED(qmp) LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG...) Would remove this ifdef from the codeflow too...> > The rest looks plausible. > > Thanks for the review, >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jun-28 10:59 UTC
Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
Ian Campbell writes ("Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client"):> I think Ian was only suggesting to remove the ifdef''s from the main flow > of code and you''ve done that for most of the uses with your DEBUG_GEN* > but here perhaps you could also define and call functions which are > empty in the non-debug case. e.g. DEBUG_GEN_START, DEBUG_GEN_END, > DEBUG_GEN_REPORT?Quite so. Thanks, Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2011-Jun-28 11:11 UTC
Re: [Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
Ian Campbell writes ("Re: [Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl."):> Using a pattern rule is something of a hack. Another option might be to > artificially split the multi pattern rule, e.g. do something like > _libxl_xxx.c: _libxl_xxx.h > > _libxl_xxx.h: libxl.idl etc etc > genwrap.py ... etc etc > mv ...This is the conventional way of solving this problem.> At first I thought the better way was your use of .NOTPARALLEL but > actually it is probably still running the rule multiple times for no > reason and you have just worked around the problem with multiple > parallel invocations of the mv''s.Yes, very likely. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-28 11:11 UTC
Re: [Xen-devel] Re: [PATCH V5 2/3] libxl: Introduce libxl_internal_types.idl.
On Tue, Jun 28, 2011 at 09:57, Ian Campbell <Ian.Campbell@eu.citrix.com> wrote:> >> >> _libxl_%.h _libxl_%.c: libxl.idl gen%.py libxl%.py >> >> $(PYTHON) gen$*.py libxl.idl __libxl_$*.h __libxl_$*.c >> > >> > If you simply s/gen$*.py/gentypes.py/ and s/libxl.idl/libxl$*.idl/g and >> > leave the other patterns does this rule work for both IDL files? >> >> Yes, it''s works, with a `mv libxl.idl libxl_types.idl`. > > Can you incorporate the _types into the rule itself or does make not > allow for % to match zero-characters?I tried, but make did not "see" the rules. So % need to be at least one characters. I could incorporate just ''_type'', so we will know that the rule is for types. -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony PERARD
2011-Jun-28 14:22 UTC
Re: [Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client
On Tue, Jun 28, 2011 at 10:14, Ian Campbell <Ian.Campbell@eu.citrix.com> wrote:> On Mon, 2011-06-27 at 18:04 +0100, Anthony PERARD wrote: >> On Mon, Jun 27, 2011 at 17:17, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote: >> > Anthony PERARD writes ("[Xen-devel] [PATCH V5 3/3] libxl, Introduce a QMP client"): >> >> 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 serial0 in xenstored. So we will be able to use xl console with >> >> QEMU upstream. >> > >> > Can I make a suggestion ? I think the formulaic json parser stuff >> > could usefully live in a separate file. >> >> Ok, I will cut the file. > > FWIW my "libxl: IDL: autogenerate functions to produce JSON from libxl > data structures" patch added libxl_json.c. If you want to add that file > with the bits you need I will rebase onto it (since I need to rework at > least this last patch of my series anyway, see below).I will look at this patch.>> >> +static inline yajl_gen_status yajl_gen_asciiz(yajl_gen hand, const >> > char *str) >> > >> > Isn''t this a hostage to fortune ? yajl may grow an identically-named >> > function in which case this will no longer build. >> >> Maybe. I will rename to libxl__yajl_gen_asciiz. > > Good idea. My patch also added yajl_gen_asciiz. I shall defer to the > version which you will have added when I rebase. > >> >> +#ifdef DEBUG_ANSWER >> >> + if (qmp->g) >> >> + yajl_gen_free(qmp->g); >> >> +#endif >> > >> > Can this #ifdef not be shuffled off somewhere ? Ie, make a debug >> > function (or macro) which we call unconditionally. >> >> Ok, I will remove all the #ifdef debug_answer. > > I think Ian was only suggesting to remove the ifdef''s from the main flow > of code and you''ve done that for most of the uses with your DEBUG_GEN* > but here perhaps you could also define and call functions which are > empty in the non-debug case. e.g. DEBUG_GEN_START, DEBUG_GEN_END, > DEBUG_GEN_REPORT?Sorry, I should say replace by macros, instead of "remove". Is it fine to keep the #ifdef inside the struct or should I remove the #ifdef and keep "yajl_gen g" field even if it will not be used (in case DEBUG_ANSWER in undef) ?> BTW I noticed: > +#ifdef DEBUG_RECEIVED > + qmp->buffer[rd] = 0; > + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "received: ''%s''", qmp->buffer); > +#endif > > I wondered if the zero termination of the string should be there even in > the non-debug case?This should not be necessary as the read size (rd) is always used.> Also is there a buffer overrun (when > rd==QMP_RECEIVE_BUFFER_SIZE)? > > If its the latter you could perhaps use > printf("%*s", rd, qmp->buf); > ?This printf seams to work better with "%.*s". I will use that, so no more zero-terminited buffer and no more buffer overrun.> Having done that then: > #define DEBUG_RECEIVED(qmp) LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG...) > Would remove this ifdef from the codeflow too...Thanks, -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel