This is a tested version of my event handling API proposal. This series contains a number of uncontroversial stylistic and bugfix patches, plus these: 02/15 libxenstore: Provide xs_check_watch 12/15 libxl: Use GC_INIT and GC_FREE everywhere 13/15 libxl: make LIBXL_INIT_GC a statement, not an initialiser 14/15 libxl: New API for providing OS events to libxl 15/15 libxl: New event generation API Changes since v3: * New patches to use GC_INIT and GC_FREE everywhere so we could change LIBXL_INIT_GC to properly initialise the new tail queue in the gc. * Bugfixes resulting from testing. Domain shutdown/death events work. Disk eject events work as well as they did beforehand, but it turns out that our cdrom insert/eject machinery is not currently working very well. This needs to be addressed separately. * Added some comments regarding #define OSEVENT_HOOK_INTERN in libxl_event.c. Please review. I would like to apply 12/15 in particular ASAP, as it is textually very intrusive. I think 01-12 ought to be pretty uncontroversial by now, and I have now tested 02/15 so I think it''s ready to go in. 14 and 15 have the meat. Ian.
Ian Jackson
2011-Dec-05 18:10 UTC
[PATCH 01/15] libxl: Make libxl__xs_* more const-correct
Paths and values which are not modified by these functions should be declared as "const char *" not "char *". Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl_internal.h | 9 +++++---- tools/libxl/libxl_xshelp.c | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 84da6b1..bfc74c9 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -172,18 +172,19 @@ _hidden char *libxl__dirname(libxl__gc *gc, const char *s); _hidden char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int length); _hidden int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t, - char *dir, char **kvs); + const char *dir, char **kvs); _hidden int libxl__xs_write(libxl__gc *gc, xs_transaction_t t, - char *path, const char *fmt, ...) PRINTF_ATTRIBUTE(4, 5); + const char *path, const char *fmt, ...) PRINTF_ATTRIBUTE(4, 5); /* Each fn returns 0 on success. * On error: returns -1, sets errno (no logging) */ _hidden char *libxl__xs_get_dompath(libxl__gc *gc, uint32_t domid); /* On error: logs, returns NULL, sets errno. */ -_hidden char *libxl__xs_read(libxl__gc *gc, xs_transaction_t t, char *path); +_hidden char *libxl__xs_read(libxl__gc *gc, xs_transaction_t t, + const char *path); _hidden char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t, - char *path, unsigned int *nb); + const char *path, unsigned int *nb); /* On error: returns NULL, sets errno (no logging) */ _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid); diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c index 4b09be3..bc4e7e4 100644 --- a/tools/libxl/libxl_xshelp.c +++ b/tools/libxl/libxl_xshelp.c @@ -49,7 +49,7 @@ char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int length) } int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t, - char *dir, char *kvs[]) + const char *dir, char *kvs[]) { libxl_ctx *ctx = libxl__gc_owner(gc); char *path; @@ -69,7 +69,7 @@ int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t, } int libxl__xs_write(libxl__gc *gc, xs_transaction_t t, - char *path, const char *fmt, ...) + const char *path, const char *fmt, ...) { libxl_ctx *ctx = libxl__gc_owner(gc); char *s; @@ -87,7 +87,7 @@ int libxl__xs_write(libxl__gc *gc, xs_transaction_t t, return 0; } -char * libxl__xs_read(libxl__gc *gc, xs_transaction_t t, char *path) +char * libxl__xs_read(libxl__gc *gc, xs_transaction_t t, const char *path) { libxl_ctx *ctx = libxl__gc_owner(gc); char *ptr; @@ -113,7 +113,8 @@ char *libxl__xs_get_dompath(libxl__gc *gc, uint32_t domid) return s; } -char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t, char *path, unsigned int *nb) +char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t, + const char *path, unsigned int *nb) { libxl_ctx *ctx = libxl__gc_owner(gc); char **ret = NULL; -- 1.7.2.5
Event-driven programs want to wait until the xs_fileno triggers for reading, and then repeatedly call xs_check_watch. Also xs_read_watch exposes a useless "num" out parameter, which should always (if things aren''t going hideously wrong) be at least 2 and which the caller shouldn''t be interested in. So xs_check_watch doesn''t have one of those. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/xenstore/xs.c | 89 ++++++++++++++++++++++++++++++++++++++++++++------- tools/xenstore/xs.h | 16 +++++++++ 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index df270f7..8e54fe0 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -132,7 +132,23 @@ struct xs_handle { #endif -static int read_message(struct xs_handle *h); +static int read_message(struct xs_handle *h, int nonblocking); + +static void setnonblock(int fd, int nonblock) { + int esave = errno; + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + goto out; + + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + + fcntl(fd, F_SETFL, flags); +out: + errno = esave; +} int xs_fileno(struct xs_handle *h) { @@ -325,8 +341,16 @@ void xs_close(struct xs_handle* xsh) xs_daemon_close(xsh); } -static bool read_all(int fd, void *data, unsigned int len) +static bool read_all(int fd, void *data, unsigned int len, int nonblocking) + /* With nonblocking, either reads either everything requested, + * or nothing. */ { + if (!len) + return true; + + if (nonblocking) + setnonblock(fd, 1); + while (len) { int done; @@ -334,18 +358,28 @@ static bool read_all(int fd, void *data, unsigned int len) if (done < 0) { if (errno == EINTR) continue; - return false; + goto out_false; } if (done == 0) { /* It closed fd on us? EBADF is appropriate. */ errno = EBADF; - return false; + goto out_false; } data += done; len -= done; + + if (nonblocking) { + setnonblock(fd, 0); + nonblocking = 0; + } } return true; + +out_false: + if (nonblocking) + setnonblock(fd, 0); + return false; } #ifdef XSTEST @@ -374,7 +408,7 @@ static void *read_reply( read_from_thread = read_thread_exists(h); /* Read from comms channel ourselves if there is no reader thread. */ - if (!read_from_thread && (read_message(h) == -1)) + if (!read_from_thread && (read_message(h, 0) == -1)) return NULL; mutex_lock(&h->reply_mutex); @@ -693,7 +727,8 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token) * Returns array of two pointers: path and token, or NULL. * Call free() after use. */ -char **xs_read_watch(struct xs_handle *h, unsigned int *num) +static char **read_watch_internal(struct xs_handle *h, unsigned int *num, + int nonblocking) { struct xs_stored_msg *msg; char **ret, *strings, c = 0; @@ -707,14 +742,20 @@ char **xs_read_watch(struct xs_handle *h, unsigned int *num) * we haven''t called xs_watch. Presumably the application * will do so later; in the meantime we just block. */ - while (list_empty(&h->watch_list) && h->fd != -1) + while (list_empty(&h->watch_list) && h->fd != -1) { + if (nonblocking) { + mutex_unlock(&h->watch_mutex); + errno = EAGAIN; + return 0; + } condvar_wait(&h->watch_condvar, &h->watch_mutex); + } #else /* !defined(USE_PTHREAD) */ /* Read from comms channel ourselves if there are no threads * and therefore no reader thread. */ assert(!read_thread_exists(h)); /* not threadsafe but worth a check */ - if ((read_message(h) == -1)) + if ((read_message(h, nonblocking) == -1)) return NULL; #endif /* !defined(USE_PTHREAD) */ @@ -760,6 +801,24 @@ char **xs_read_watch(struct xs_handle *h, unsigned int *num) return ret; } +char **xs_check_watch(struct xs_handle *h) +{ + unsigned int num; + char **ret; + ret = read_watch_internal(h, &num, 1); + if (ret) assert(num >= 2); + return ret; +} + +/* Find out what node change was on (will block if nothing pending). + * Returns array of two pointers: path and token, or NULL. + * Call free() after use. + */ +char **xs_read_watch(struct xs_handle *h, unsigned int *num) +{ + return read_watch_internal(h, num, 0); +} + /* Remove a watch on a node. * Returns false on failure (no watch on that node). */ @@ -940,11 +999,17 @@ char *xs_debug_command(struct xs_handle *h, const char *cmd, ARRAY_SIZE(iov), NULL); } -static int read_message(struct xs_handle *h) +static int read_message(struct xs_handle *h, int nonblocking) { /* IMPORTANT: It is forbidden to call this function without * acquiring the request lock and checking that h->read_thr_exists * is false. See "Lock discipline" in struct xs_handle, above. */ + + /* If nonblocking==1, this function will always read either + * nothing, returning -1 and setting errno==EAGAIN, or we read + * whole amount requested. Ie as soon as we have the start of + * the message we block until we get all of it. + */ struct xs_stored_msg *msg = NULL; char *body = NULL; @@ -956,7 +1021,7 @@ static int read_message(struct xs_handle *h) if (msg == NULL) goto error; cleanup_push(free, msg); - if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr))) { /* Cancellation point */ + if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr), nonblocking)) { /* Cancellation point */ saved_errno = errno; goto error_freemsg; } @@ -966,7 +1031,7 @@ static int read_message(struct xs_handle *h) if (body == NULL) goto error_freemsg; cleanup_push(free, body); - if (!read_all(h->fd, body, msg->hdr.len)) { /* Cancellation point */ + if (!read_all(h->fd, body, msg->hdr.len, 0)) { /* Cancellation point */ saved_errno = errno; goto error_freebody; } @@ -1021,7 +1086,7 @@ static void *read_thread(void *arg) struct xs_handle *h = arg; int fd; - while (read_message(h) != -1) + while (read_message(h, 0) != -1) continue; /* An error return from read_message leaves the socket in an undefined diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index 1cbe255..63f535d 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -135,6 +135,22 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token); /* Return the FD to poll on to see if a watch has fired. */ int xs_fileno(struct xs_handle *h); +/* Check for node changes. On success, returns a non-NULL pointer ret + * such that ret[0] and ret[1] are valid C strings, namely the + * triggering path (see docs/misc/xenstore.txt) and the token (from + * xs_watch). On error return value is NULL setting errno. + * + * Callers should, after xs_fileno has become readable, repeatedly + * call xs_check_watch until it returns NULL and sets errno to EAGAIN. + * (If the fd became readable, xs_check_watch is allowed to make it no + * longer show up as readable even if future calls to xs_check_watch + * will return more watch events.) + * + * After the caller is finished with the returned information it + * should be freed all in one go with free(ret). + */ +char **xs_check_watch(struct xs_handle *h); + /* Find out what node change was on (will block if nothing pending). * Returns array containing the path and token. Use XS_WATCH_* to access these * elements. Call free() after use. -- 1.7.2.5
Ian Jackson
2011-Dec-05 18:10 UTC
[PATCH 03/15] libxl: Provide a version of bsd''s queue.h as _libxl_list.h
We would like some linked list macros which are (a) well known to be sane and (b) typesafe. BSD''s queue.h meets these criteria. We also provide some simple perlery to arrange to add the libxl_ namespace prefix to the macros. This will allow us to #include _libxl_list.h in our public header file without clashing with anyone else who is also using another version of queue.h. (A note on copyright: The FreeBSD files we are adding have an [L]GPL-compatible licence, so there is no need to change our COPYING. Although FreeBSD''s queue.3 still contains the advertising clause, this has been withdrawn by UCB as recorded in the FreeBSD COPYRIGHT file, which is included in tools/libxl/external/ for reference.) Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <Ian.campbell@citrix.com> Tested-by: Roger Pau Monne <roger.pau@entel.upc.edu> --- tools/libxl/Makefile | 10 +- tools/libxl/bsd-sys-queue-h-seddery | 70 +++ tools/libxl/external/README | 14 + tools/libxl/external/bsd-COPYRIGHT | 126 ++++ tools/libxl/external/bsd-queue.3 | 1044 ++++++++++++++++++++++++++++++++++ tools/libxl/external/bsd-sys-queue.h | 637 +++++++++++++++++++++ 6 files changed, 1898 insertions(+), 3 deletions(-) create mode 100755 tools/libxl/bsd-sys-queue-h-seddery create mode 100644 tools/libxl/external/README create mode 100644 tools/libxl/external/bsd-COPYRIGHT create mode 100644 tools/libxl/external/bsd-queue.3 create mode 100644 tools/libxl/external/bsd-sys-queue.h diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index a7a4625..f363da2 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -42,7 +42,7 @@ LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) -AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h +AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h _libxl_list.h AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \ libxlu_disk_l.o libxlu_disk.o @@ -55,7 +55,7 @@ $(XL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h $(XL_OBJS): CFLAGS += $(CFLAGS_libxenlight) testidl.o: CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenlight) -testidl.c: libxl_types.idl gentest.py libxl.h +testidl.c: libxl_types.idl gentest.py libxl.h $(AUTOINCS) $(PYTHON) gentest.py libxl_types.idl testidl.c.new mv testidl.c.new testidl.c @@ -63,7 +63,7 @@ testidl.c: libxl_types.idl gentest.py libxl.h all: $(CLIENTS) libxenlight.so libxenlight.a libxlutil.so libxlutil.a \ $(AUTOSRCS) $(AUTOINCS) -$(LIBXLU_OBJS): $(AUTOINCS) +$(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): $(AUTOINCS) %.c %.h: %.y @rm -f $*.[ch] @@ -81,6 +81,10 @@ _libxl_paths.h: genpath rm -f $@.tmp $(call move-if-changed,$@.2.tmp,$@) +_libxl_list.h: bsd-sys-queue-h-seddery external/bsd-sys-queue.h + perl ./$^ --prefix=libxl >$@.new + $(call move-if-changed,$@.new,$@) + libxl_paths.c: _libxl_paths.h libxl.h: _libxl_types.h diff --git a/tools/libxl/bsd-sys-queue-h-seddery b/tools/libxl/bsd-sys-queue-h-seddery new file mode 100755 index 0000000..c0aa079 --- /dev/null +++ b/tools/libxl/bsd-sys-queue-h-seddery @@ -0,0 +1,70 @@ +#!/usr/bin/perl -p +# +# This script is part of the Xen build system. It has a very +# permissive licence to avoid complicating the licence of the +# generated header file and to allow this seddery to be reused by +# other projects. +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this individual file (the "Software"), to deal +# in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, +# sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the +# following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Copyright (C) 2011 Citrix Ltd + +our $namespace, $ucnamespace; + +BEGIN { + die unless @ARGV; + $namespace = pop @ARGV; + $namespace =~ s/^--prefix=// or die; + $ucnamespace = uc $namespace; + + print <<END or die $!; +/* + * DO NOT EDIT THIS FILE + * + * Generated automatically by bsd-sys-queue-h-seddery to + * - introduce ${ucnamespace}_ and ${namespace}_ namespace prefixes + * - turn "struct type" into "type" so that type arguments + * to the macros are type names not struct tags + * - remove the reference to sys/cdefs.h, which is not needed + * + * The purpose of this seddery is to allow the resulting file to be + * freely included by software which might also want to include other + * list macros; to make it usable when struct tags are not being used + * or not known; to make it more portable. + */ +END +} + +s/\b( _SYS_QUEUE | + SLIST | LIST | STAILQ | TAILQ | QUEUE + )/${ucnamespace}_$1/xg; + +s/\b( TRACEBUF | TRASHIT | + QMD_ + )/${ucnamespace}__$1/xg; + +s/\b( + qm_ + )/${namespace}__$1/xg; + +s/\b struct \s+ type \b/type/xg; + +s,^\#include.*sys/cdefs.*,/* $& */,xg; diff --git a/tools/libxl/external/README b/tools/libxl/external/README new file mode 100644 index 0000000..8c8beea --- /dev/null +++ b/tools/libxl/external/README @@ -0,0 +1,14 @@ +WARNING - DO NOT EDIT THINGS IN THIS DIRECTORY (apart from this README) +----------------------------------------------------------------------- + +These files were obtained elsewhere and should only be updated by +copying new versions from the source location, as documented below: + +bsd-COPYRIGHT +bsd-sys-queue.h +bsd-queue.3 + + Obtained from the FreeBSD SVN using the following commands: + svn co -r 221843 svn://svn.freebsd.org/base/head/sys/sys/ + svn co -r 221843 svn://svn.freebsd.org/base/head/share/man/man3 + svn cat -r 221843 http://svn.freebsd.org/base/head/COPYRIGHT >tools/libxl/external/bsd-COPYRIGHT diff --git a/tools/libxl/external/bsd-COPYRIGHT b/tools/libxl/external/bsd-COPYRIGHT new file mode 100644 index 0000000..6dc5d16 --- /dev/null +++ b/tools/libxl/external/bsd-COPYRIGHT @@ -0,0 +1,126 @@ +# $FreeBSD$ +# @(#)COPYRIGHT 8.2 (Berkeley) 3/21/94 + +The compilation of software known as FreeBSD is distributed under the +following terms: + +Copyright (c) 1992-2011 The FreeBSD Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'''' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +The 4.4BSD and 4.4BSD-Lite software is distributed under the following +terms: + +All of the documentation and software included in the 4.4BSD and 4.4BSD-Lite +Releases is copyrighted by The Regents of the University of California. + +Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by the University of +California, Berkeley and its contributors. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'''' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +The Institute of Electrical and Electronics Engineers and the American +National Standards Committee X3, on Information Processing Systems have +given us permission to reprint portions of their documentation. + +In the following statement, the phrase ``this text'''' refers to portions +of the system documentation. + +Portions of this text are reprinted and reproduced in electronic form in +the second BSD Networking Software Release, from IEEE Std 1003.1-1988, IEEE +Standard Portable Operating System Interface for Computer Environments +(POSIX), copyright C 1988 by the Institute of Electrical and Electronics +Engineers, Inc. In the event of any discrepancy between these versions +and the original IEEE Standard, the original IEEE Standard is the referee +document. + +In the following statement, the phrase ``This material'''' refers to portions +of the system documentation. + +This material is reproduced with permission from American National +Standards Committee X3, on Information Processing Systems. Computer and +Business Equipment Manufacturers Association (CBEMA), 311 First St., NW, +Suite 500, Washington, DC 20001-2178. The developmental work of +Programming Language C was completed by the X3J11 Technical Committee. + +The views and conclusions contained in the software and documentation are +those of the authors and should not be interpreted as representing official +policies, either expressed or implied, of the Regents of the University +of California. + + +NOTE: The copyright of UC Berkeley''s Berkeley Software Distribution ("BSD") +source has been updated. The copyright addendum may be found at +ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change and is +included below. + +July 22, 1999 + +To All Licensees, Distributors of Any Version of BSD: + +As you know, certain of the Berkeley Software Distribution ("BSD") source +code files require that further distributions of products containing all or +portions of the software, acknowledge within their advertising materials +that such products contain software developed by UC Berkeley and its +contributors. + +Specifically, the provision reads: + +" * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors." + +Effective immediately, licensees and distributors are no longer required to +include the acknowledgement within advertising materials. Accordingly, the +foregoing paragraph of those BSD Unix files containing it is hereby deleted +in its entirety. + +William Hoskins +Director, Office of Technology Licensing +University of California, Berkeley diff --git a/tools/libxl/external/bsd-queue.3 b/tools/libxl/external/bsd-queue.3 new file mode 100644 index 0000000..007ca5c --- /dev/null +++ b/tools/libxl/external/bsd-queue.3 @@ -0,0 +1,1044 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'''' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)queue.3 8.2 (Berkeley) 1/24/94 +.\" $FreeBSD$ +.\" +.Dd May 13, 2011 +.Dt QUEUE 3 +.Os +.Sh NAME +.Nm SLIST_EMPTY , +.Nm SLIST_ENTRY , +.Nm SLIST_FIRST , +.Nm SLIST_FOREACH , +.Nm SLIST_FOREACH_SAFE , +.Nm SLIST_HEAD , +.Nm SLIST_HEAD_INITIALIZER , +.Nm SLIST_INIT , +.Nm SLIST_INSERT_AFTER , +.Nm SLIST_INSERT_HEAD , +.Nm SLIST_NEXT , +.Nm SLIST_REMOVE_AFTER , +.Nm SLIST_REMOVE_HEAD , +.Nm SLIST_REMOVE , +.Nm SLIST_SWAP , +.Nm STAILQ_CONCAT , +.Nm STAILQ_EMPTY , +.Nm STAILQ_ENTRY , +.Nm STAILQ_FIRST , +.Nm STAILQ_FOREACH , +.Nm STAILQ_FOREACH_SAFE , +.Nm STAILQ_HEAD , +.Nm STAILQ_HEAD_INITIALIZER , +.Nm STAILQ_INIT , +.Nm STAILQ_INSERT_AFTER , +.Nm STAILQ_INSERT_HEAD , +.Nm STAILQ_INSERT_TAIL , +.Nm STAILQ_LAST , +.Nm STAILQ_NEXT , +.Nm STAILQ_REMOVE_AFTER , +.Nm STAILQ_REMOVE_HEAD , +.Nm STAILQ_REMOVE , +.Nm STAILQ_SWAP , +.Nm LIST_EMPTY , +.Nm LIST_ENTRY , +.Nm LIST_FIRST , +.Nm LIST_FOREACH , +.Nm LIST_FOREACH_SAFE , +.Nm LIST_HEAD , +.Nm LIST_HEAD_INITIALIZER , +.Nm LIST_INIT , +.Nm LIST_INSERT_AFTER , +.Nm LIST_INSERT_BEFORE , +.Nm LIST_INSERT_HEAD , +.Nm LIST_NEXT , +.Nm LIST_REMOVE , +.Nm LIST_SWAP , +.Nm TAILQ_CONCAT , +.Nm TAILQ_EMPTY , +.Nm TAILQ_ENTRY , +.Nm TAILQ_FIRST , +.Nm TAILQ_FOREACH , +.Nm TAILQ_FOREACH_SAFE , +.Nm TAILQ_FOREACH_REVERSE , +.Nm TAILQ_FOREACH_REVERSE_SAFE , +.Nm TAILQ_HEAD , +.Nm TAILQ_HEAD_INITIALIZER , +.Nm TAILQ_INIT , +.Nm TAILQ_INSERT_AFTER , +.Nm TAILQ_INSERT_BEFORE , +.Nm TAILQ_INSERT_HEAD , +.Nm TAILQ_INSERT_TAIL , +.Nm TAILQ_LAST , +.Nm TAILQ_NEXT , +.Nm TAILQ_PREV , +.Nm TAILQ_REMOVE , +.Nm TAILQ_SWAP +.Nd implementations of singly-linked lists, singly-linked tail queues, +lists and tail queues +.Sh SYNOPSIS +.In sys/queue.h +.\" +.Fn SLIST_EMPTY "SLIST_HEAD *head" +.Fn SLIST_ENTRY "TYPE" +.Fn SLIST_FIRST "SLIST_HEAD *head" +.Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" +.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var" +.Fn SLIST_HEAD "HEADNAME" "TYPE" +.Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head" +.Fn SLIST_INIT "SLIST_HEAD *head" +.Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME" +.Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME" +.Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME" +.Fn SLIST_REMOVE_AFTER "TYPE *elm" "SLIST_ENTRY NAME" +.Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME" +.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME" +.Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "SLIST_ENTRY NAME" +.\" +.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" +.Fn STAILQ_EMPTY "STAILQ_HEAD *head" +.Fn STAILQ_ENTRY "TYPE" +.Fn STAILQ_FIRST "STAILQ_HEAD *head" +.Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" +.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var" +.Fn STAILQ_HEAD "HEADNAME" "TYPE" +.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head" +.Fn STAILQ_INIT "STAILQ_HEAD *head" +.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE" "STAILQ_ENTRY NAME" +.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME" +.Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "STAILQ_ENTRY NAME" +.\" +.Fn LIST_EMPTY "LIST_HEAD *head" +.Fn LIST_ENTRY "TYPE" +.Fn LIST_FIRST "LIST_HEAD *head" +.Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" +.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var" +.Fn LIST_HEAD "HEADNAME" "TYPE" +.Fn LIST_HEAD_INITIALIZER "LIST_HEAD head" +.Fn LIST_INIT "LIST_HEAD *head" +.Fn LIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME" +.Fn LIST_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME" +.Fn LIST_INSERT_HEAD "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME" +.Fn LIST_NEXT "TYPE *elm" "LIST_ENTRY NAME" +.Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME" +.Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME" +.\" +.Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME" +.Fn TAILQ_EMPTY "TAILQ_HEAD *head" +.Fn TAILQ_ENTRY "TYPE" +.Fn TAILQ_FIRST "TAILQ_HEAD *head" +.Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" +.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var" +.Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" +.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var" +.Fn TAILQ_HEAD "HEADNAME" "TYPE" +.Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head" +.Fn TAILQ_INIT "TAILQ_HEAD *head" +.Fn TAILQ_INSERT_AFTER "TAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_INSERT_HEAD "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_INSERT_TAIL "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_LAST "TAILQ_HEAD *head" "HEADNAME" +.Fn TAILQ_NEXT "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_PREV "TYPE *elm" "HEADNAME" "TAILQ_ENTRY NAME" +.Fn TAILQ_REMOVE "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME" +.Fn TAILQ_SWAP "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TYPE" "TAILQ_ENTRY NAME" +.\" +.Sh DESCRIPTION +These macros define and operate on four types of data structures: +singly-linked lists, singly-linked tail queues, lists, and tail queues. +All four structures support the following functionality: +.Bl -enum -compact -offset indent +.It +Insertion of a new entry at the head of the list. +.It +Insertion of a new entry after any element in the list. +.It +O(1) removal of an entry from the head of the list. +.It +Forward traversal through the list. +.It +Swawpping the contents of two lists. +.El +.Pp +Singly-linked lists are the simplest of the four data structures +and support only the above functionality. +Singly-linked lists are ideal for applications with large datasets +and few or no removals, +or for implementing a LIFO queue. +Singly-linked lists add the following functionality: +.Bl -enum -compact -offset indent +.It +O(n) removal of any entry in the list. +.El +.Pp +Singly-linked tail queues add the following functionality: +.Bl -enum -compact -offset indent +.It +Entries can be added at the end of a list. +.It +O(n) removal of any entry in the list. +.It +They may be concatenated. +.El +However: +.Bl -enum -compact -offset indent +.It +All list insertions must specify the head of the list. +.It +Each head entry requires two pointers rather than one. +.It +Code size is about 15% greater and operations run about 20% slower +than singly-linked lists. +.El +.Pp +Singly-linked tailqs are ideal for applications with large datasets and +few or no removals, +or for implementing a FIFO queue. +.Pp +All doubly linked types of data structures (lists and tail queues) +additionally allow: +.Bl -enum -compact -offset indent +.It +Insertion of a new entry before any element in the list. +.It +O(1) removal of any entry in the list. +.El +However: +.Bl -enum -compact -offset indent +.It +Each element requires two pointers rather than one. +.It +Code size and execution time of operations (except for removal) is about +twice that of the singly-linked data-structures. +.El +.Pp +Linked lists are the simplest of the doubly linked data structures and support +only the above functionality over singly-linked lists. +.Pp +Tail queues add the following functionality: +.Bl -enum -compact -offset indent +.It +Entries can be added at the end of a list. +.It +They may be traversed backwards, from tail to head. +.It +They may be concatenated. +.El +However: +.Bl -enum -compact -offset indent +.It +All list insertions and removals must specify the head of the list. +.It +Each head entry requires two pointers rather than one. +.It +Code size is about 15% greater and operations run about 20% slower +than singly-linked lists. +.El +.Pp +In the macro definitions, +.Fa TYPE +is the name of a user defined structure, +that must contain a field of type +.Li SLIST_ENTRY , +.Li STAILQ_ENTRY , +.Li LIST_ENTRY , +or +.Li TAILQ_ENTRY , +named +.Fa NAME . +The argument +.Fa HEADNAME +is the name of a user defined structure that must be declared +using the macros +.Li SLIST_HEAD , +.Li STAILQ_HEAD , +.Li LIST_HEAD , +or +.Li TAILQ_HEAD . +See the examples below for further explanation of how these +macros are used. +.Sh SINGLY-LINKED LISTS +A singly-linked list is headed by a structure defined by the +.Nm SLIST_HEAD +macro. +This structure contains a single pointer to the first element +on the list. +The elements are singly linked for minimum space and pointer manipulation +overhead at the expense of O(n) removal for arbitrary elements. +New elements can be added to the list after an existing element or +at the head of the list. +An +.Fa SLIST_HEAD +structure is declared as follows: +.Bd -literal -offset indent +SLIST_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and +.Fa TYPE +is the type of the elements to be linked into the list. +A pointer to the head of the list can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The macro +.Nm SLIST_HEAD_INITIALIZER +evaluates to an initializer for the list +.Fa head . +.Pp +The macro +.Nm SLIST_EMPTY +evaluates to true if there are no elements in the list. +.Pp +The macro +.Nm SLIST_ENTRY +declares a structure that connects the elements in +the list. +.Pp +The macro +.Nm SLIST_FIRST +returns the first element in the list or NULL if the list is empty. +.Pp +The macro +.Nm SLIST_FOREACH +traverses the list referenced by +.Fa head +in the forward direction, assigning each element in +turn to +.Fa var . +.Pp +The macro +.Nm SLIST_FOREACH_SAFE +traverses the list referenced by +.Fa head +in the forward direction, assigning each element in +turn to +.Fa var . +However, unlike +.Fn SLIST_FOREACH +here it is permitted to both remove +.Fa var +as well as free it from within the loop safely without interfering with the +traversal. +.Pp +The macro +.Nm SLIST_INIT +initializes the list referenced by +.Fa head . +.Pp +The macro +.Nm SLIST_INSERT_HEAD +inserts the new element +.Fa elm +at the head of the list. +.Pp +The macro +.Nm SLIST_INSERT_AFTER +inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The macro +.Nm SLIST_NEXT +returns the next element in the list. +.Pp +The macro +.Nm SLIST_REMOVE_AFTER +removes the element after +.Fa elm +from the list. Unlike +.Fa SLIST_REMOVE , +this macro does not traverse the entire list. +.Pp +The macro +.Nm SLIST_REMOVE_HEAD +removes the element +.Fa elm +from the head of the list. +For optimum efficiency, +elements being removed from the head of the list should explicitly use +this macro instead of the generic +.Fa SLIST_REMOVE +macro. +.Pp +The macro +.Nm SLIST_REMOVE +removes the element +.Fa elm +from the list. +.Pp +The macro +.Nm SLIST_SWAP +swaps the contents of +.Fa head1 +and +.Fa head2 . +.Sh SINGLY-LINKED LIST EXAMPLE +.Bd -literal +SLIST_HEAD(slisthead, entry) head + SLIST_HEAD_INITIALIZER(head); +struct slisthead *headp; /* Singly-linked List head. */ +struct entry { + ... + SLIST_ENTRY(entry) entries; /* Singly-linked List. */ + ... +} *n1, *n2, *n3, *np; + +SLIST_INIT(&head); /* Initialize the list. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +SLIST_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +SLIST_INSERT_AFTER(n1, n2, entries); + +SLIST_REMOVE(&head, n2, entry, entries);/* Deletion. */ +free(n2); + +n3 = SLIST_FIRST(&head); +SLIST_REMOVE_HEAD(&head, entries); /* Deletion from the head. */ +free(n3); + /* Forward traversal. */ +SLIST_FOREACH(np, &head, entries) + np-> ... + /* Safe forward traversal. */ +SLIST_FOREACH_SAFE(np, &head, entries, np_temp) { + np->do_stuff(); + ... + SLIST_REMOVE(&head, np, entry, entries); + free(np); +} + +while (!SLIST_EMPTY(&head)) { /* List Deletion. */ + n1 = SLIST_FIRST(&head); + SLIST_REMOVE_HEAD(&head, entries); + free(n1); +} +.Ed +.Sh SINGLY-LINKED TAIL QUEUES +A singly-linked tail queue is headed by a structure defined by the +.Nm STAILQ_HEAD +macro. +This structure contains a pair of pointers, +one to the first element in the tail queue and the other to +the last element in the tail queue. +The elements are singly linked for minimum space and pointer +manipulation overhead at the expense of O(n) removal for arbitrary +elements. +New elements can be added to the tail queue after an existing element, +at the head of the tail queue, or at the end of the tail queue. +A +.Fa STAILQ_HEAD +structure is declared as follows: +.Bd -literal -offset indent +STAILQ_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Li HEADNAME +is the name of the structure to be defined, and +.Li TYPE +is the type of the elements to be linked into the tail queue. +A pointer to the head of the tail queue can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The macro +.Nm STAILQ_HEAD_INITIALIZER +evaluates to an initializer for the tail queue +.Fa head . +.Pp +The macro +.Nm STAILQ_CONCAT +concatenates the tail queue headed by +.Fa head2 +onto the end of the one headed by +.Fa head1 +removing all entries from the former. +.Pp +The macro +.Nm STAILQ_EMPTY +evaluates to true if there are no items on the tail queue. +.Pp +The macro +.Nm STAILQ_ENTRY +declares a structure that connects the elements in +the tail queue. +.Pp +The macro +.Nm STAILQ_FIRST +returns the first item on the tail queue or NULL if the tail queue +is empty. +.Pp +The macro +.Nm STAILQ_FOREACH +traverses the tail queue referenced by +.Fa head +in the forward direction, assigning each element +in turn to +.Fa var . +.Pp +The macro +.Nm STAILQ_FOREACH_SAFE +traverses the tail queue referenced by +.Fa head +in the forward direction, assigning each element +in turn to +.Fa var . +However, unlike +.Fn STAILQ_FOREACH +here it is permitted to both remove +.Fa var +as well as free it from within the loop safely without interfering with the +traversal. +.Pp +The macro +.Nm STAILQ_INIT +initializes the tail queue referenced by +.Fa head . +.Pp +The macro +.Nm STAILQ_INSERT_HEAD +inserts the new element +.Fa elm +at the head of the tail queue. +.Pp +The macro +.Nm STAILQ_INSERT_TAIL +inserts the new element +.Fa elm +at the end of the tail queue. +.Pp +The macro +.Nm STAILQ_INSERT_AFTER +inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The macro +.Nm STAILQ_LAST +returns the last item on the tail queue. +If the tail queue is empty the return value is +.Dv NULL . +.Pp +The macro +.Nm STAILQ_NEXT +returns the next item on the tail queue, or NULL this item is the last. +.Pp +The macro +.Nm STAILQ_REMOVE_AFTER +removes the element after +.Fa elm +from the tail queue. Unlike +.Fa STAILQ_REMOVE , +this macro does not traverse the entire tail queue. +.Pp +The macro +.Nm STAILQ_REMOVE_HEAD +removes the element at the head of the tail queue. +For optimum efficiency, +elements being removed from the head of the tail queue should +use this macro explicitly rather than the generic +.Fa STAILQ_REMOVE +macro. +.Pp +The macro +.Nm STAILQ_REMOVE +removes the element +.Fa elm +from the tail queue. +.Pp +The macro +.Nm STAILQ_SWAP +swaps the contents of +.Fa head1 +and +.Fa head2 . +.Sh SINGLY-LINKED TAIL QUEUE EXAMPLE +.Bd -literal +STAILQ_HEAD(stailhead, entry) head + STAILQ_HEAD_INITIALIZER(head); +struct stailhead *headp; /* Singly-linked tail queue head. */ +struct entry { + ... + STAILQ_ENTRY(entry) entries; /* Tail queue. */ + ... +} *n1, *n2, *n3, *np; + +STAILQ_INIT(&head); /* Initialize the queue. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +STAILQ_INSERT_HEAD(&head, n1, entries); + +n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */ +STAILQ_INSERT_TAIL(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +STAILQ_INSERT_AFTER(&head, n1, n2, entries); + /* Deletion. */ +STAILQ_REMOVE(&head, n2, entry, entries); +free(n2); + /* Deletion from the head. */ +n3 = STAILQ_FIRST(&head); +STAILQ_REMOVE_HEAD(&head, entries); +free(n3); + /* Forward traversal. */ +STAILQ_FOREACH(np, &head, entries) + np-> ... + /* Safe forward traversal. */ +STAILQ_FOREACH_SAFE(np, &head, entries, np_temp) { + np->do_stuff(); + ... + STAILQ_REMOVE(&head, np, entry, entries); + free(np); +} + /* TailQ Deletion. */ +while (!STAILQ_EMPTY(&head)) { + n1 = STAILQ_FIRST(&head); + STAILQ_REMOVE_HEAD(&head, entries); + free(n1); +} + /* Faster TailQ Deletion. */ +n1 = STAILQ_FIRST(&head); +while (n1 != NULL) { + n2 = STAILQ_NEXT(n1, entries); + free(n1); + n1 = n2; +} +STAILQ_INIT(&head); +.Ed +.Sh LISTS +A list is headed by a structure defined by the +.Nm LIST_HEAD +macro. +This structure contains a single pointer to the first element +on the list. +The elements are doubly linked so that an arbitrary element can be +removed without traversing the list. +New elements can be added to the list after an existing element, +before an existing element, or at the head of the list. +A +.Fa LIST_HEAD +structure is declared as follows: +.Bd -literal -offset indent +LIST_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and +.Fa TYPE +is the type of the elements to be linked into the list. +A pointer to the head of the list can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The macro +.Nm LIST_HEAD_INITIALIZER +evaluates to an initializer for the list +.Fa head . +.Pp +The macro +.Nm LIST_EMPTY +evaluates to true if there are no elements in the list. +.Pp +The macro +.Nm LIST_ENTRY +declares a structure that connects the elements in +the list. +.Pp +The macro +.Nm LIST_FIRST +returns the first element in the list or NULL if the list +is empty. +.Pp +The macro +.Nm LIST_FOREACH +traverses the list referenced by +.Fa head +in the forward direction, assigning each element in turn to +.Fa var . +.Pp +The macro +.Nm LIST_FOREACH_SAFE +traverses the list referenced by +.Fa head +in the forward direction, assigning each element in turn to +.Fa var . +However, unlike +.Fn LIST_FOREACH +here it is permitted to both remove +.Fa var +as well as free it from within the loop safely without interfering with the +traversal. +.Pp +The macro +.Nm LIST_INIT +initializes the list referenced by +.Fa head . +.Pp +The macro +.Nm LIST_INSERT_HEAD +inserts the new element +.Fa elm +at the head of the list. +.Pp +The macro +.Nm LIST_INSERT_AFTER +inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The macro +.Nm LIST_INSERT_BEFORE +inserts the new element +.Fa elm +before the element +.Fa listelm . +.Pp +The macro +.Nm LIST_NEXT +returns the next element in the list, or NULL if this is the last. +.Pp +The macro +.Nm LIST_REMOVE +removes the element +.Fa elm +from the list. +.Pp +The macro +.Nm LIST_SWAP +swaps the contents of +.Fa head1 +and +.Fa head2 . +.Sh LIST EXAMPLE +.Bd -literal +LIST_HEAD(listhead, entry) head + LIST_HEAD_INITIALIZER(head); +struct listhead *headp; /* List head. */ +struct entry { + ... + LIST_ENTRY(entry) entries; /* List. */ + ... +} *n1, *n2, *n3, *np, *np_temp; + +LIST_INIT(&head); /* Initialize the list. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +LIST_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +LIST_INSERT_AFTER(n1, n2, entries); + +n3 = malloc(sizeof(struct entry)); /* Insert before. */ +LIST_INSERT_BEFORE(n2, n3, entries); + +LIST_REMOVE(n2, entries); /* Deletion. */ +free(n2); + /* Forward traversal. */ +LIST_FOREACH(np, &head, entries) + np-> ... + + /* Safe forward traversal. */ +LIST_FOREACH_SAFE(np, &head, entries, np_temp) { + np->do_stuff(); + ... + LIST_REMOVE(np, entries); + free(np); +} + +while (!LIST_EMPTY(&head)) { /* List Deletion. */ + n1 = LIST_FIRST(&head); + LIST_REMOVE(n1, entries); + free(n1); +} + +n1 = LIST_FIRST(&head); /* Faster List Deletion. */ +while (n1 != NULL) { + n2 = LIST_NEXT(n1, entries); + free(n1); + n1 = n2; +} +LIST_INIT(&head); +.Ed +.Sh TAIL QUEUES +A tail queue is headed by a structure defined by the +.Nm TAILQ_HEAD +macro. +This structure contains a pair of pointers, +one to the first element in the tail queue and the other to +the last element in the tail queue. +The elements are doubly linked so that an arbitrary element can be +removed without traversing the tail queue. +New elements can be added to the tail queue after an existing element, +before an existing element, at the head of the tail queue, +or at the end of the tail queue. +A +.Fa TAILQ_HEAD +structure is declared as follows: +.Bd -literal -offset indent +TAILQ_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Li HEADNAME +is the name of the structure to be defined, and +.Li TYPE +is the type of the elements to be linked into the tail queue. +A pointer to the head of the tail queue can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The macro +.Nm TAILQ_HEAD_INITIALIZER +evaluates to an initializer for the tail queue +.Fa head . +.Pp +The macro +.Nm TAILQ_CONCAT +concatenates the tail queue headed by +.Fa head2 +onto the end of the one headed by +.Fa head1 +removing all entries from the former. +.Pp +The macro +.Nm TAILQ_EMPTY +evaluates to true if there are no items on the tail queue. +.Pp +The macro +.Nm TAILQ_ENTRY +declares a structure that connects the elements in +the tail queue. +.Pp +The macro +.Nm TAILQ_FIRST +returns the first item on the tail queue or NULL if the tail queue +is empty. +.Pp +The macro +.Nm TAILQ_FOREACH +traverses the tail queue referenced by +.Fa head +in the forward direction, assigning each element in turn to +.Fa var . +.Fa var +is set to +.Dv NULL +if the loop completes normally, or if there were no elements. +.Pp +The macro +.Nm TAILQ_FOREACH_REVERSE +traverses the tail queue referenced by +.Fa head +in the reverse direction, assigning each element in turn to +.Fa var . +.Pp +The macros +.Nm TAILQ_FOREACH_SAFE +and +.Nm TAILQ_FOREACH_REVERSE_SAFE +traverse the list referenced by +.Fa head +in the forward or reverse direction respectively, +assigning each element in turn to +.Fa var . +However, unlike their unsafe counterparts, +.Nm TAILQ_FOREACH +and +.Nm TAILQ_FOREACH_REVERSE +permit to both remove +.Fa var +as well as free it from within the loop safely without interfering with the +traversal. +.Pp +The macro +.Nm TAILQ_INIT +initializes the tail queue referenced by +.Fa head . +.Pp +The macro +.Nm TAILQ_INSERT_HEAD +inserts the new element +.Fa elm +at the head of the tail queue. +.Pp +The macro +.Nm TAILQ_INSERT_TAIL +inserts the new element +.Fa elm +at the end of the tail queue. +.Pp +The macro +.Nm TAILQ_INSERT_AFTER +inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The macro +.Nm TAILQ_INSERT_BEFORE +inserts the new element +.Fa elm +before the element +.Fa listelm . +.Pp +The macro +.Nm TAILQ_LAST +returns the last item on the tail queue. +If the tail queue is empty the return value is +.Dv NULL . +.Pp +The macro +.Nm TAILQ_NEXT +returns the next item on the tail queue, or NULL if this item is the last. +.Pp +The macro +.Nm TAILQ_PREV +returns the previous item on the tail queue, or NULL if this item +is the first. +.Pp +The macro +.Nm TAILQ_REMOVE +removes the element +.Fa elm +from the tail queue. +.Pp +The macro +.Nm TAILQ_SWAP +swaps the contents of +.Fa head1 +and +.Fa head2 . +.Sh TAIL QUEUE EXAMPLE +.Bd -literal +TAILQ_HEAD(tailhead, entry) head + TAILQ_HEAD_INITIALIZER(head); +struct tailhead *headp; /* Tail queue head. */ +struct entry { + ... + TAILQ_ENTRY(entry) entries; /* Tail queue. */ + ... +} *n1, *n2, *n3, *np; + +TAILQ_INIT(&head); /* Initialize the queue. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +TAILQ_INSERT_HEAD(&head, n1, entries); + +n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */ +TAILQ_INSERT_TAIL(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +TAILQ_INSERT_AFTER(&head, n1, n2, entries); + +n3 = malloc(sizeof(struct entry)); /* Insert before. */ +TAILQ_INSERT_BEFORE(n2, n3, entries); + +TAILQ_REMOVE(&head, n2, entries); /* Deletion. */ +free(n2); + /* Forward traversal. */ +TAILQ_FOREACH(np, &head, entries) + np-> ... + /* Safe forward traversal. */ +TAILQ_FOREACH_SAFE(np, &head, entries, np_temp) { + np->do_stuff(); + ... + TAILQ_REMOVE(&head, np, entries); + free(np); +} + /* Reverse traversal. */ +TAILQ_FOREACH_REVERSE(np, &head, tailhead, entries) + np-> ... + /* TailQ Deletion. */ +while (!TAILQ_EMPTY(&head)) { + n1 = TAILQ_FIRST(&head); + TAILQ_REMOVE(&head, n1, entries); + free(n1); +} + /* Faster TailQ Deletion. */ +n1 = TAILQ_FIRST(&head); +while (n1 != NULL) { + n2 = TAILQ_NEXT(n1, entries); + free(n1); + n1 = n2; +} +TAILQ_INIT(&head); +.Ed +.Sh SEE ALSO +.Xr tree 3 +.Sh HISTORY +The +.Nm queue +functions first appeared in +.Bx 4.4 . diff --git a/tools/libxl/external/bsd-sys-queue.h b/tools/libxl/external/bsd-sys-queue.h new file mode 100644 index 0000000..274e636 --- /dev/null +++ b/tools/libxl/external/bsd-sys-queue.h @@ -0,0 +1,637 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'''' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include <sys/cdefs.h> + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ -- 1.7.2.5
Ian Jackson
2011-Dec-05 18:10 UTC
[PATCH 04/15] libxl: idl: support new "private" type attribute
This provides for fields in libxl datatypes which are only present in the C version of structures and are used only by libxl itself. This is useful when a libxl datatype wants to contain fields which are used by libxl internally and which are only present in the structure to avoid additional memory allocation inconvenience. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/gentest.py | 2 ++ tools/libxl/libxltypes.py | 4 +++- tools/python/genwrap.py | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py index 05e77cc..ac7a400 100644 --- a/tools/libxl/gentest.py +++ b/tools/libxl/gentest.py @@ -56,6 +56,8 @@ def gen_rand_init(ty, v, indent = " ", parent = None): s += "%s = rand() %% 2;\n" % v elif ty.typename in ["char *"]: s += "%s = rand_str();\n" % v + elif ty.private: + pass elif ty.typename in handcoded: raise Exception("Gen for handcoded %s" % ty.typename) else: diff --git a/tools/libxl/libxltypes.py b/tools/libxl/libxltypes.py index 55056c2..450de88 100644 --- a/tools/libxl/libxltypes.py +++ b/tools/libxl/libxltypes.py @@ -33,6 +33,8 @@ class Type(object): if self.passby not in [PASS_BY_VALUE, PASS_BY_REFERENCE]: raise ValueError + self.private = kwargs.setdefault(''private'', False) + if typename is None: # Anonymous type self.typename = None self.rawname = None @@ -50,7 +52,7 @@ class Type(object): self.autogenerate_dispose_fn = kwargs.setdefault(''autogenerate_dispose_fn'', True) - if self.typename is not None: + if self.typename is not None and not self.private: self.json_fn = kwargs.setdefault(''json_fn'', self.typename + "_gen_json") else: self.json_fn = kwargs.setdefault(''json_fn'', None) diff --git a/tools/python/genwrap.py b/tools/python/genwrap.py index d0c193d..ecbec11 100644 --- a/tools/python/genwrap.py +++ b/tools/python/genwrap.py @@ -129,6 +129,8 @@ static PyObject *Py%(rawname)s_new(PyTypeObject *type, PyObject *args, PyObject l.append(''static PyGetSetDef Py%s_getset[] = {''%ty.rawname) for f in ty.fields: + if f.type.private: + continue l.append('' { .name = "%s", ''%f.name) if ty.marshal_out(): l.append('' .get = (getter)py_%s_%s_get, ''%(ty.rawname, f.name)) @@ -295,9 +297,14 @@ _hidden int genwrap__ll_set(PyObject *v, long long *val, long long mask); """ % tuple(('' ''.join(sys.argv),) + (os.path.split(decls)[-1:]),)) for ty in types: + if ty.private: + continue if isinstance(ty, libxltypes.Aggregate): f.write(''/* Attribute get/set functions for %s */\n''%ty.typename) for a in ty.fields: + print >>sys.stderr, `a`, `ty`, `a.type`, `a.type.__dict__` + if a.type.private: + continue if ty.marshal_out(): f.write(py_attrib_get(ty,a)) if ty.marshal_in(): -- 1.7.2.5
Instead of generating: typedef struct { ... } libxl_foo; Produce: typedef struct libxl_foo { ... } libxl_foo; This makes it possible to refer to libxl idl-generated structs and unions, as incomplete types, before they have been defined. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/gentypes.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/tools/libxl/gentypes.py b/tools/libxl/gentypes.py index d8f43e3..7ca6375 100644 --- a/tools/libxl/gentypes.py +++ b/tools/libxl/gentypes.py @@ -56,7 +56,7 @@ def libxl_C_type_define(ty, indent = ""): if ty.typename is None: s += "%s {\n" % ty.kind else: - s += "typedef %s {\n" % ty.kind + s += "typedef %s %s {\n" % (ty.kind, ty.typename) for f in ty.fields: if f.comment is not None: -- 1.7.2.5
GCC and C99 allow declarations to be mixed with code. This is a good idea because: * It allows variables to be more often initialised as they are declared, thus reducing the occurrence of uninitialised variable errors. * Certain alloca-like constructs (arrays allocated at runtime on the stack) can more often be written without a spurious { } block. Such blocks are confusing to read. * It makes it easier to write and use macros which declare and initialise formulaic variables and do other function setup code, because there is no need to worry that such macros might be incompatible with each other or have strict ordering constraints. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/Makefile | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index f363da2..4e0f3fb 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -11,7 +11,8 @@ MINOR = 0 XLUMAJOR = 1.0 XLUMINOR = 0 -CFLAGS += -Werror -Wno-format-zero-length -Wmissing-declarations +CFLAGS += -Werror -Wno-format-zero-length -Wmissing-declarations \ + -Wno-declaration-after-statement CFLAGS += -I. -fPIC ifeq ($(CONFIG_Linux),y) -- 1.7.2.5
Provide some macros which are useful shorthands for use within libxl: * GC_INIT to initialise a gc from a ctx and GC_FREE to free it * CTX(gc) to give you back the ctx * LIBXL_TAILQ_INSERT_SORTED for inserting things into sorted lists These will be used by later patches. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl_internal.h | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 48 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index bfc74c9..950c466 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -646,6 +646,54 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s); _hidden libxl_device_model_version libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); + +/* + * Convenience macros. + */ + + +/* + * All of these assume (or define) + * libxl__gc *gc; + * as a local variable. + */ + +#define GC_INIT(ctx) libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) } +#define GC_FREE libxl__free_all(gc) +#define CTX libxl__gc_owner(gc) + + +/* + * Inserts "elm_new" into the sorted list "head". + * + * "elm_search" must be a loop search variable of the same type as + * "elm_new". "new_after_search_p" must be an expression which is + * true iff the element "elm_new" sorts after the element + * "elm_search". + * + * "search_body" can be empty, or some declaration(s) and statement(s) + * needed for "new_after_search_p". + */ +#define LIBXL_TAILQ_INSERT_SORTED(head, entry, elm_new, elm_search, \ + search_body, new_after_search_p) \ + do { \ + for ((elm_search) = LIBXL_TAILQ_FIRST((head)); \ + (elm_search); \ + (elm_search) = LIBXL_TAILQ_NEXT((elm_search), entry)) { \ + search_body; \ + if (!(new_after_search_p)) \ + break; \ + } \ + /* now elm_search is either the element before which we want \ + * to place elm_new, or NULL meaning we want to put elm_new at \ + * the end */ \ + if ((elm_search)) \ + LIBXL_TAILQ_INSERT_BEFORE((elm_search), (elm_new), entry); \ + else \ + LIBXL_TAILQ_INSERT_TAIL((head), (elm_new), entry); \ + } while(0) + + #endif /* -- 1.7.2.5
libxl_internal.h now #includes libxl.h and various system headers. This 1. makes the order of header inclusion more predictable 2. explicitly allows libxl_internal.h to use objects defined in libxl.h 3. removes the need for individual files to include these headers Also - remove some unnecessary #includes of libxl_utils.h, flexarray.h, etc. in some libxl*.c files, - include libxl_osdeps.h at the top of libxl_internal.h - add missing includes of libxl_osdeps.h to a couple of files - change libxl.h to libxl_internal.h in a couple of files Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl.c | 3 --- tools/libxl/libxl_blktap2.c | 1 - tools/libxl/libxl_bootloader.c | 4 ---- tools/libxl/libxl_cpuid.c | 4 ---- tools/libxl/libxl_create.c | 4 +--- tools/libxl/libxl_device.c | 1 - tools/libxl/libxl_dm.c | 4 +--- tools/libxl/libxl_dom.c | 1 - tools/libxl/libxl_exec.c | 1 - tools/libxl/libxl_flask.c | 3 ++- tools/libxl/libxl_internal.c | 4 ---- tools/libxl/libxl_internal.h | 5 +++++ tools/libxl/libxl_json.c | 3 ++- tools/libxl/libxl_noblktap2.c | 2 -- tools/libxl/libxl_nocpuid.c | 2 +- tools/libxl/libxl_paths.c | 2 +- tools/libxl/libxl_pci.c | 5 ----- tools/libxl/libxl_qmp.c | 2 ++ tools/libxl/libxl_utils.c | 1 - tools/libxl/libxl_uuid.c | 4 ++++ tools/libxl/libxl_xshelp.c | 1 - 21 files changed, 19 insertions(+), 38 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index a171142..bc17b15 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -31,10 +31,7 @@ #include <inttypes.h> #include <assert.h> -#include "libxl.h" -#include "libxl_utils.h" #include "libxl_internal.h" -#include "flexarray.h" #define PAGE_TO_MEMKB(pages) ((pages) * 4) #define BACKEND_STRING_SIZE 5 diff --git a/tools/libxl/libxl_blktap2.c b/tools/libxl/libxl_blktap2.c index c8d9148..acf4110 100644 --- a/tools/libxl/libxl_blktap2.c +++ b/tools/libxl/libxl_blktap2.c @@ -12,7 +12,6 @@ * GNU Lesser General Public License for more details. */ -#include "libxl.h" #include "libxl_osdeps.h" #include "libxl_internal.h" diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c index 47bb3a1..b8399a1 100644 --- a/tools/libxl/libxl_bootloader.c +++ b/tools/libxl/libxl_bootloader.c @@ -14,7 +14,6 @@ #include "libxl_osdeps.h" -#include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> @@ -22,11 +21,8 @@ #include <sys/stat.h> #include <sys/types.h> -#include "libxl.h" #include "libxl_internal.h" -#include "flexarray.h" - #define XENCONSOLED_BUF_SIZE 16 #define BOOTLOADER_BUF_SIZE 4096 #define BOOTLOADER_TIMEOUT 1 diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c index 78bcab5..56a00cd 100644 --- a/tools/libxl/libxl_cpuid.c +++ b/tools/libxl/libxl_cpuid.c @@ -10,10 +10,6 @@ * GNU Lesser General Public License for more details. */ -#include <string.h> - -#include "libxl.h" -#include "libxl_osdeps.h" #include "libxl_internal.h" void libxl_cpuid_dispose(libxl_cpuid_policy_list *p_cpuid_list) diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index ce6a55e..ccb56c7 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -26,10 +26,8 @@ #include <xc_dom.h> #include <xenguest.h> #include <assert.h> -#include "libxl.h" -#include "libxl_utils.h" + #include "libxl_internal.h" -#include "flexarray.h" void libxl_domain_config_dispose(libxl_domain_config *d_config) { diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index a53fb70..46254ea 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -24,7 +24,6 @@ #include <unistd.h> #include <fcntl.h> -#include "libxl.h" #include "libxl_internal.h" char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device) diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index cef80be..05c83cd 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -24,10 +24,8 @@ #include <unistd.h> #include <fcntl.h> #include <assert.h> -#include "libxl_utils.h" + #include "libxl_internal.h" -#include "libxl.h" -#include "flexarray.h" static const char *libxl_tapif_script(libxl__gc *gc) { diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index b74db34..96098de 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -32,7 +32,6 @@ #include <xen/hvm/hvm_info_table.h> -#include "libxl.h" #include "libxl_internal.h" libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid) diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c index 1a62d47..52d40d1 100644 --- a/tools/libxl/libxl_exec.c +++ b/tools/libxl/libxl_exec.c @@ -28,7 +28,6 @@ #include <signal.h> /* for SIGKILL */ #include <fcntl.h> -#include "libxl.h" #include "libxl_internal.h" static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int *status, int options) diff --git a/tools/libxl/libxl_flask.c b/tools/libxl/libxl_flask.c index c8d0594..6b548dd 100644 --- a/tools/libxl/libxl_flask.c +++ b/tools/libxl/libxl_flask.c @@ -7,13 +7,14 @@ * as published by the Free Software Foundation. */ +#include "libxl_osdeps.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <xenctrl.h> -#include "libxl.h" #include "libxl_internal.h" int libxl_flask_context_to_sid(libxl_ctx *ctx, char *buf, size_t len, diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index 34edaf3..d767ce3 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -16,8 +16,6 @@ #include "libxl_osdeps.h" #include <stdio.h> -#include <stdarg.h> -#include <string.h> #include <sys/types.h> #include <sys/stat.h> @@ -25,9 +23,7 @@ #include <sys/mman.h> #include <unistd.h> -#include "libxl.h" #include "libxl_internal.h" -#include "libxl_utils.h" int libxl__error_set(libxl__gc *gc, int code) { diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 950c466..cda6fc1 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -17,14 +17,19 @@ #ifndef LIBXL_INTERNAL_H #define LIBXL_INTERNAL_H +#include "libxl_osdeps.h" + #include <stdint.h> #include <stdarg.h> #include <stdlib.h> +#include <string.h> #include <xs.h> #include <xenctrl.h> #include "xentoollog.h" +#include "libxl.h" + #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #define _hidden __attribute__((visibility("hidden"))) #define _protected __attribute__((visibility("protected"))) diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c index fd5e2aa..c0f869e 100644 --- a/tools/libxl/libxl_json.c +++ b/tools/libxl/libxl_json.c @@ -12,6 +12,8 @@ * GNU Lesser General Public License for more details. */ +#include "libxl_osdeps.h" + #include <assert.h> #include <string.h> #include <math.h> @@ -19,7 +21,6 @@ #include <yajl/yajl_parse.h> #include <yajl/yajl_gen.h> -#include <libxl.h> #include "libxl_internal.h" /* #define DEBUG_ANSWER */ diff --git a/tools/libxl/libxl_noblktap2.c b/tools/libxl/libxl_noblktap2.c index 704d03f..3307551 100644 --- a/tools/libxl/libxl_noblktap2.c +++ b/tools/libxl/libxl_noblktap2.c @@ -12,8 +12,6 @@ * GNU Lesser General Public License for more details. */ -#include "libxl.h" -#include "libxl_osdeps.h" #include "libxl_internal.h" int libxl__blktap_enabled(libxl__gc *gc) diff --git a/tools/libxl/libxl_nocpuid.c b/tools/libxl/libxl_nocpuid.c index d63757f..2e9490c 100644 --- a/tools/libxl/libxl_nocpuid.c +++ b/tools/libxl/libxl_nocpuid.c @@ -10,7 +10,7 @@ * GNU Lesser General Public License for more details. */ -#include "libxl.h" +#include "libxl_internal.h" void libxl_cpuid_destroy(libxl_cpuid_policy_list *p_cpuid_list) { diff --git a/tools/libxl/libxl_paths.c b/tools/libxl/libxl_paths.c index c84e51d..e7bd1a2 100644 --- a/tools/libxl/libxl_paths.c +++ b/tools/libxl/libxl_paths.c @@ -12,7 +12,7 @@ * GNU Lesser General Public License for more details. */ -#include "libxl.h" +#include "libxl_internal.h" #include "_libxl_paths.h" const char *libxl_sbindir_path(void) diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index 4186cf8..63c3050 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -17,7 +17,6 @@ #include "libxl_osdeps.h" #include <stdio.h> -#include <string.h> #include <stdlib.h> #include <sys/types.h> #include <fcntl.h> @@ -27,15 +26,11 @@ #include <sys/stat.h> #include <signal.h> #include <unistd.h> /* for write, unlink and close */ -#include <stdint.h> #include <inttypes.h> #include <dirent.h> #include <assert.h> -#include "libxl.h" -#include "libxl_utils.h" #include "libxl_internal.h" -#include "flexarray.h" #define PCI_BDF "%04x:%02x:%02x.%01x" #define PCI_BDF_SHORT "%02x:%02x.%01x" diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c index f749e01..c7696d7 100644 --- a/tools/libxl/libxl_qmp.c +++ b/tools/libxl/libxl_qmp.c @@ -18,6 +18,8 @@ * Specification, see in the QEMU repository. */ +#include "libxl_osdeps.h" + #include <unistd.h> #include <sys/un.h> #include <sys/queue.h> diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index 1fa2c0f..f1f2a6d 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -28,7 +28,6 @@ #include <unistd.h> #include <assert.h> -#include "libxl_utils.h" #include "libxl_internal.h" struct schedid_name { diff --git a/tools/libxl/libxl_uuid.c b/tools/libxl/libxl_uuid.c index e837228..80ab789 100644 --- a/tools/libxl/libxl_uuid.c +++ b/tools/libxl/libxl_uuid.c @@ -12,8 +12,12 @@ * GNU Lesser General Public License for more details. */ +#include "libxl_osdeps.h" + #include <libxl_uuid.h> +#include "libxl_internal.h" + #if defined(__linux__) int libxl_uuid_is_nil(libxl_uuid *uuid) diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c index bc4e7e4..ea835e2 100644 --- a/tools/libxl/libxl_xshelp.c +++ b/tools/libxl/libxl_xshelp.c @@ -21,7 +21,6 @@ #include <stdarg.h> #include <inttypes.h> -#include "libxl.h" #include "libxl_internal.h" char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int length) -- 1.7.2.5
This lock will be used to protect data structures which will be hung off the libxl_ctx in subsequent patches. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl.c | 6 ++++++ tools/libxl/libxl_internal.h | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index bc17b15..7488538 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -41,6 +41,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, { libxl_ctx *ctx; struct stat stat_buf; + const pthread_mutex_t mutex_value = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; if (version != LIBXL_VERSION) return ERROR_VERSION; @@ -54,6 +55,11 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, memset(ctx, 0, sizeof(libxl_ctx)); ctx->lg = lg; + /* This somewhat convoluted approach is needed because + * PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is defined to be valid + * only as an initialiser, not as an expression. */ + memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); + if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" "failed to stat %s", XENSTORE_PID_FILE); diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index cda6fc1..41de6fd 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -23,6 +23,7 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <pthread.h> #include <xs.h> #include <xenctrl.h> @@ -95,6 +96,18 @@ struct libxl__ctx { xc_interface *xch; struct xs_handle *xsh; + pthread_mutex_t lock; /* protects data structures hanging off the ctx */ + /* Always use CTX_LOCK and CTX_UNLOCK to manipulate this. + * + * You may acquire this mutex recursively if it is convenient to + * do so. You may not acquire this lock at the same time as any + * other lock. If you need to call application code outside + * libxl (ie, a callback) with this lock held then it is + * necessaray to impose restrictions on the caller to maintain a + * proper lock hierarchy, and these restrictions must then be + * documented in the libxl public interface. + */ + /* for callers who reap children willy-nilly; caller must only * set this after libxl_init and before any other call - or * may leave them untouched */ @@ -668,6 +681,20 @@ libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); #define CTX libxl__gc_owner(gc) +/* Locking functions. See comment for "lock" member of libxl__ctx. */ + +#define CTX_LOCK do { \ + int mutex_r = pthread_mutex_lock(&CTX->lock); \ + assert(!mutex_r); \ + } while(0) + +#define CTX_UNLOCK do { \ + int mutex_r = pthread_mutex_unlock(&CTX->lock); \ + assert(!mutex_r); \ + } while(0) + + + /* * Inserts "elm_new" into the sorted list "head". * -- 1.7.2.5
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl_internal.c | 4 ++-- tools/libxl/libxl_internal.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index d767ce3..ae28cb0 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -179,7 +179,7 @@ char *libxl__dirname(libxl__gc *gc, const char *s) void libxl__logv(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, const char *file, int line, const char *func, - char *fmt, va_list ap) + const char *fmt, va_list ap) { char *enomem = "[out of memory formatting log message]"; char *base = NULL; @@ -206,7 +206,7 @@ void libxl__logv(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, void libxl__log(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, const char *file, int line, const char *func, - char *fmt, ...) + const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 41de6fd..1d1dc35 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -80,13 +80,13 @@ _hidden void libxl__logv(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, const char *file /* may be 0 */, int line /* ignored if !file */, const char *func /* may be 0 */, - char *fmt, va_list al) + const char *fmt, va_list al) __attribute__((format(printf,7,0))); _hidden void libxl__log(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, const char *file /* may be 0 */, int line /* ignored if !file */, const char *func /* may be 0 */, - char *fmt, ...) + const char *fmt, ...) __attribute__((format(printf,7,8))); /* these functions preserve errno (saving and restoring) */ -- 1.7.2.5
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl_internal.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index ae28cb0..a2e5820 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -72,6 +72,8 @@ void libxl__free_all(libxl__gc *gc) free(ptr); } free(gc->alloc_ptrs); + gc->alloc_ptrs = 0; + gc->alloc_maxsize = 0; } void *libxl__zalloc(libxl__gc *gc, int bytes) -- 1.7.2.5
Replace libxl__gc gc = LIBXL_INIT_GC(ctx); ... libxl__free_all(&gc); with GC_INIT(ctx); ... GC_FREE; throughout with a couple of perl runes. We must then adjust uses of the resulting gc for pointerness, which is mostly just replacing all occurrences of "&gc" with "gc". Also a couple of unusual uses of LIBXL_INIT_GC needed to be fixed up by hand. Here are those runes: perl -i -pe ''s/\Q libxl__gc gc = LIBXL_INIT_GC(ctx);/ GC_INIT(ctx);/'' tools/libxl/*.c perl -i -pe ''s/\Q libxl__free_all(&gc);/ GC_FREE;/'' tools/libxl/*.c Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/libxl.c | 590 ++++++++++++++++++++-------------------- tools/libxl/libxl_bootloader.c | 14 +- tools/libxl/libxl_create.c | 12 +- tools/libxl/libxl_dom.c | 16 +- tools/libxl/libxl_pci.c | 34 ++-- tools/libxl/libxl_qmp.c | 32 +- tools/libxl/libxl_utils.c | 36 ++-- 7 files changed, 367 insertions(+), 367 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 7488538..3a8cfe3 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -232,19 +232,19 @@ int libxl__domain_rename(libxl__gc *gc, uint32_t domid, int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid, const char *old_name, const char *new_name) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = libxl__domain_rename(&gc, domid, old_name, new_name, XBT_NULL); - libxl__free_all(&gc); + rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL); + GC_FREE; return rc; } int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc = 0; - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Called domain_resume on " "non-cooperative hvm domain %u", domid); rc = ERROR_NI; @@ -264,7 +264,7 @@ int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid) rc = ERROR_FAIL; } out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -277,7 +277,7 @@ out: int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); struct xs_permissions roperm[2]; xs_transaction_t t; char *preserved_name; @@ -287,27 +287,27 @@ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, int rc; - preserved_name = libxl__sprintf(&gc, "%s%s", info->name, name_suffix); + preserved_name = libxl__sprintf(gc, "%s%s", info->name, name_suffix); if (!preserved_name) { - libxl__free_all(&gc); + GC_FREE; return ERROR_NOMEM; } - uuid_string = libxl__uuid2string(&gc, new_uuid); + uuid_string = libxl__uuid2string(gc, new_uuid); if (!uuid_string) { - libxl__free_all(&gc); + GC_FREE; return ERROR_NOMEM; } - dom_path = libxl__xs_get_dompath(&gc, domid); + dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } - vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string); + vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string); if (!vm_path) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } @@ -323,20 +323,20 @@ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, xs_mkdir(ctx->xsh, t, vm_path); xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm)); - xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); - rc = libxl__domain_rename(&gc, domid, info->name, preserved_name, t); + xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); + rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t); if (rc) { - libxl__free_all(&gc); + GC_FREE; return rc; } - xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); + xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; - libxl__free_all(&gc); + GC_FREE; return 0; } @@ -478,16 +478,16 @@ libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm) int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info, uint32_t domid, int fd) { - libxl__gc gc = LIBXL_INIT_GC(ctx); - libxl_domain_type type = libxl__domain_type(&gc, domid); + GC_INIT(ctx); + libxl_domain_type type = libxl__domain_type(gc, domid); int live = info != NULL && info->flags & XL_SUSPEND_LIVE; int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG; int rc = 0; - rc = libxl__domain_suspend_common(&gc, domid, fd, type, live, debug); + rc = libxl__domain_suspend_common(gc, domid, fd, type, live, debug); if (!rc && type == LIBXL_DOMAIN_TYPE_HVM) - rc = libxl__domain_save_device_model(&gc, domid, fd); - libxl__free_all(&gc); + rc = libxl__domain_save_device_model(gc, domid, fd); + GC_FREE; return rc; } @@ -517,17 +517,17 @@ int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid, int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *path; char *state; int ret, rc = 0; - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { - path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d/state", domid); - state = libxl__xs_read(&gc, XBT_NULL, path); + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { + path = libxl__sprintf(gc, "/local/domain/0/device-model/%d/state", domid); + state = libxl__xs_read(gc, XBT_NULL, path); if (state != NULL && !strcmp(state, "paused")) { - libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "continue"); - libxl__wait_for_device_model(&gc, domid, "running", + libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/0/device-model/%d/command", domid), "continue"); + libxl__wait_for_device_model(gc, domid, "running", NULL, NULL, NULL); } } @@ -536,7 +536,7 @@ int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid) LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unpausing domain %d", domid); rc = ERROR_FAIL; } - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -550,42 +550,42 @@ static char *req_table[] = { int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *shutdown_path; char *dom_path; if (req > ARRAY_SIZE(req_table)) { - libxl__free_all(&gc); + GC_FREE; return ERROR_INVAL; } - dom_path = libxl__xs_get_dompath(&gc, domid); + dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { unsigned long pvdriver = 0; int ret; ret = xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting HVM callback IRQ"); - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } if (!pvdriver) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "HVM domain without PV drivers:" " graceful shutdown not possible, use destroy"); - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } } - shutdown_path = libxl__sprintf(&gc, "%s/control/shutdown", dom_path); + shutdown_path = libxl__sprintf(gc, "%s/control/shutdown", dom_path); xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req])); - libxl__free_all(&gc); + GC_FREE; return 0; } @@ -607,7 +607,7 @@ int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *wa int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int i, rc = -1; uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid); @@ -616,7 +616,7 @@ int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_devic for (i = 0; i < num_disks; i++) { if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", - libxl__xs_get_dompath(&gc, domid), + libxl__xs_get_dompath(gc, domid), libxl__device_disk_dev_number(disks[i].vdev, NULL, NULL)) < 0) goto out; @@ -626,7 +626,7 @@ int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_devic } rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -680,22 +680,22 @@ int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_even int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *path; char *backend; char *value; char backend_type[BACKEND_STRING_SIZE+1]; - value = libxl__xs_read(&gc, XBT_NULL, event->path); + value = libxl__xs_read(gc, XBT_NULL, event->path); if (!value || strcmp(value, "eject")) { - libxl__free_all(&gc); + GC_FREE; return 0; } path = strdup(event->path); path[strlen(path) - 6] = ''\0''; - backend = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", path)); + backend = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend", path)); sscanf(backend, "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE) "[a-z]/%*d/%*d", @@ -711,19 +711,19 @@ int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event disk->pdev_path = strdup(""); disk->format = LIBXL_DISK_FORMAT_EMPTY; /* this value is returned to the user: do not free right away */ - disk->vdev = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/dev", backend), NULL); + disk->vdev = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "%s/dev", backend), NULL); disk->removable = 1; disk->readwrite = 0; disk->is_cdrom = 1; free(path); - libxl__free_all(&gc); + GC_FREE; return 1; } int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl_dominfo dominfo; char *dom_path; char *vm_path; @@ -740,40 +740,40 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) return rc; } - switch (libxl__domain_type(&gc, domid)) { + switch (libxl__domain_type(gc, domid)) { case LIBXL_DOMAIN_TYPE_HVM: dm_present = 1; break; case LIBXL_DOMAIN_TYPE_PV: - pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid)); + pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/image/device-model-pid", domid)); dm_present = (pid != NULL); break; default: abort(); } - dom_path = libxl__xs_get_dompath(&gc, domid); + dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { rc = ERROR_FAIL; goto out; } - if (libxl__device_pci_destroy_all(&gc, domid) < 0) + if (libxl__device_pci_destroy_all(gc, domid) < 0) LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid); rc = xc_domain_pause(ctx->xch, domid); if (rc < 0) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid); } if (dm_present) { - if (libxl__destroy_device_model(&gc, domid) < 0) + 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); + libxl__qmp_cleanup(gc, domid); } - if (libxl__devices_destroy(&gc, domid, force) < 0) + if (libxl__devices_destroy(gc, domid, force) < 0) LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_devices_dispose failed for %d", domid); - vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path)); + vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dom_path)); if (vm_path) if (!xs_rm(ctx->xsh, XBT_NULL, vm_path)) LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", vm_path); @@ -781,9 +781,9 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) if (!xs_rm(ctx->xsh, XBT_NULL, dom_path)) LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", dom_path); - xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(&gc, domid)); + xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid)); - libxl__userdata_destroyall(&gc, domid); + libxl__userdata_destroyall(gc, domid); rc = xc_domain_destroy(ctx->xch, domid); if (rc < 0) { @@ -793,16 +793,16 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) } rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_console_type type) { - libxl__gc gc = LIBXL_INIT_GC(ctx); - char *p = libxl__sprintf(&gc, "%s/xenconsole", libxl_private_bindir_path()); - char *domid_s = libxl__sprintf(&gc, "%d", domid); - char *cons_num_s = libxl__sprintf(&gc, "%d", cons_num); + GC_INIT(ctx); + char *p = libxl__sprintf(gc, "%s/xenconsole", libxl_private_bindir_path()); + char *domid_s = libxl__sprintf(gc, "%d", domid); + char *cons_num_s = libxl__sprintf(gc, "%d", cons_num); char *cons_type_s; switch (type) { @@ -819,20 +819,20 @@ int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_conso execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s, (void *)NULL); out: - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm); int rc; if (stubdomid) rc = libxl_console_exec(ctx, stubdomid, STUBDOM_CONSOLE_SERIAL, LIBXL_CONSOLE_TYPE_PV); else { - switch (libxl__domain_type(&gc, domid_vm)) { + switch (libxl__domain_type(gc, domid_vm)) { case LIBXL_DOMAIN_TYPE_HVM: rc = libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSOLE_TYPE_SERIAL); break; @@ -843,13 +843,13 @@ int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm) abort(); } } - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); const char *vnc_port; const char *vnc_listen = NULL, *vnc_pass = NULL; int port = 0, autopass_fd = -1; @@ -860,19 +860,19 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) NULL, }; - vnc_port = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, + vnc_port = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "/local/domain/%d/console/vnc-port", domid)); if ( vnc_port ) port = atoi(vnc_port) - 5900; - vnc_listen = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, + vnc_listen = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "/local/domain/%d/console/vnc-listen", domid)); if ( autopass ) - vnc_pass = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, + vnc_pass = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "/local/domain/%d/console/vnc-pass", domid)); if ( NULL == vnc_listen ) @@ -881,7 +881,7 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) if ( (vnc_bin = getenv("VNCVIEWER")) ) args[0] = vnc_bin; - args[1] = libxl__sprintf(&gc, "%s:%d", vnc_listen, port); + args[1] = libxl__sprintf(gc, "%s:%d", vnc_listen, port); if ( vnc_pass ) { char tmpname[] = "/tmp/vncautopass.XXXXXX"; @@ -916,7 +916,7 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) abort(); x_fail: - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } @@ -970,17 +970,17 @@ static int libxl__device_from_disk(libxl__gc *gc, uint32_t domid, int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); flexarray_t *front; flexarray_t *back; char *dev; libxl__device device; int major, minor, rc; - rc = libxl__device_disk_set_backend(&gc, disk); + rc = libxl__device_disk_set_backend(gc, disk); if (rc) goto out; - rc = libxl__device_disk_set_backend(&gc, disk); + rc = libxl__device_disk_set_backend(gc, disk); if (rc) goto out; front = flexarray_make(16, 1); @@ -1001,7 +1001,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis goto out_free; } - rc = libxl__device_from_disk(&gc, domid, disk, &device); + rc = libxl__device_from_disk(gc, domid, disk, &device); if (rc != 0) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported" " virtual disk identifier %s", disk->vdev); @@ -1014,7 +1014,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis do_backend_phy: libxl__device_physdisk_major_minor(dev, &major, &minor); flexarray_append(back, "physical-device"); - flexarray_append(back, libxl__sprintf(&gc, "%x:%x", major, minor)); + flexarray_append(back, libxl__sprintf(gc, "%x:%x", major, minor)); flexarray_append(back, "params"); flexarray_append(back, dev); @@ -1022,13 +1022,13 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD); break; case LIBXL_DISK_BACKEND_TAP: - dev = libxl__blktap_devpath(&gc, disk->pdev_path, disk->format); + dev = libxl__blktap_devpath(gc, disk->pdev_path, disk->format); if (!dev) { rc = ERROR_FAIL; goto out_free; } flexarray_append(back, "tapdisk-params"); - flexarray_append(back, libxl__sprintf(&gc, "%s:%s", + flexarray_append(back, libxl__sprintf(gc, "%s:%s", libxl__device_disk_string_of_format(disk->format), disk->pdev_path)); @@ -1036,7 +1036,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis goto do_backend_phy; case LIBXL_DISK_BACKEND_QDISK: flexarray_append(back, "params"); - flexarray_append(back, libxl__sprintf(&gc, "%s:%s", + flexarray_append(back, libxl__sprintf(gc, "%s:%s", libxl__device_disk_string_of_format(disk->format), disk->pdev_path)); assert(device.backend_kind == LIBXL__DEVICE_KIND_QDISK); break; @@ -1047,15 +1047,15 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis } flexarray_append(back, "frontend-id"); - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); flexarray_append(back, "online"); flexarray_append(back, "1"); flexarray_append(back, "removable"); - flexarray_append(back, libxl__sprintf(&gc, "%d", (disk->removable) ? 1 : 0)); + flexarray_append(back, libxl__sprintf(gc, "%d", (disk->removable) ? 1 : 0)); flexarray_append(back, "bootable"); - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); flexarray_append(back, "state"); - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); flexarray_append(back, "dev"); flexarray_append(back, disk->vdev); flexarray_append(back, "type"); @@ -1066,17 +1066,17 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis flexarray_append(back, disk->is_cdrom ? "cdrom" : "disk"); flexarray_append(front, "backend-id"); - flexarray_append(front, libxl__sprintf(&gc, "%d", disk->backend_domid)); + flexarray_append(front, libxl__sprintf(gc, "%d", disk->backend_domid)); flexarray_append(front, "state"); - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); flexarray_append(front, "virtual-device"); - flexarray_append(front, libxl__sprintf(&gc, "%d", device.devid)); + flexarray_append(front, libxl__sprintf(gc, "%d", device.devid)); flexarray_append(front, "device-type"); flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk"); - libxl__device_generic_add(&gc, &device, - libxl__xs_kvs_of_flexarray(&gc, back, back->count), - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); + libxl__device_generic_add(gc, &device, + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count)); rc = 0; @@ -1084,39 +1084,39 @@ out_free: flexarray_free(back); flexarray_free(front); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_disk(&gc, domid, disk, &device); + rc = libxl__device_from_disk(gc, domid, disk, &device); if (rc != 0) goto out; - rc = libxl__device_remove(&gc, &device, 1); + rc = libxl__device_remove(gc, &device, 1); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_disk_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_disk(&gc, domid, disk, &device); + rc = libxl__device_from_disk(gc, domid, disk, &device); if (rc != 0) goto out; - rc = libxl__device_destroy(&gc, &device); + rc = libxl__device_destroy(gc, &device); out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1168,27 +1168,27 @@ static void libxl__device_disk_from_xs_be(libxl__gc *gc, int libxl_devid_to_device_disk(libxl_ctx *ctx, uint32_t domid, int devid, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *dompath, *path; int rc = ERROR_FAIL; libxl_device_disk_init(ctx, disk); - dompath = libxl__xs_get_dompath(&gc, domid); + dompath = libxl__xs_get_dompath(gc, domid); if (!dompath) { goto out; } - path = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, "%s/device/vbd/%d/backend", + path = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%s/device/vbd/%d/backend", dompath, devid)); if (!path) goto out; - libxl__device_disk_from_xs_be(&gc, path, disk); + libxl__device_disk_from_xs_be(gc, path, disk); rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1228,22 +1228,22 @@ static int libxl__append_disk_list_of_type(libxl__gc *gc, libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl_device_disk *disks = NULL; int rc; *num = 0; - rc = libxl__append_disk_list_of_type(&gc, domid, "vbd", &disks, num); + rc = libxl__append_disk_list_of_type(gc, domid, "vbd", &disks, num); if (rc) goto out_err; - rc = libxl__append_disk_list_of_type(&gc, domid, "tap", &disks, num); + rc = libxl__append_disk_list_of_type(gc, domid, "tap", &disks, num); if (rc) goto out_err; - rc = libxl__append_disk_list_of_type(&gc, domid, "qdisk", &disks, num); + rc = libxl__append_disk_list_of_type(gc, domid, "qdisk", &disks, num); if (rc) goto out_err; - libxl__free_all(&gc); + GC_FREE; return disks; out_err: @@ -1259,35 +1259,35 @@ out_err: int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk, libxl_diskinfo *diskinfo) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *dompath, *diskpath; char *val; - dompath = libxl__xs_get_dompath(&gc, domid); + dompath = libxl__xs_get_dompath(gc, domid); diskinfo->devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL); /* tap devices entries in xenstore are written as vbd devices. */ - diskpath = libxl__sprintf(&gc, "%s/device/vbd/%d", dompath, diskinfo->devid); + diskpath = libxl__sprintf(gc, "%s/device/vbd/%d", dompath, diskinfo->devid); diskinfo->backend = xs_read(ctx->xsh, XBT_NULL, - libxl__sprintf(&gc, "%s/backend", diskpath), NULL); + libxl__sprintf(gc, "%s/backend", diskpath), NULL); if (!diskinfo->backend) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", diskpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend-id", diskpath)); diskinfo->backend_id = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", diskpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/state", diskpath)); diskinfo->state = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", diskpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/event-channel", diskpath)); diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/ring-ref", diskpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/ring-ref", diskpath)); diskinfo->rref = val ? strtoul(val, NULL, 10) : -1; diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL, - libxl__sprintf(&gc, "%s/frontend", diskinfo->backend), NULL); - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", diskinfo->backend)); + libxl__sprintf(gc, "%s/frontend", diskinfo->backend), NULL); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/frontend-id", diskinfo->backend)); diskinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1; - libxl__free_all(&gc); + GC_FREE; return 0; } @@ -1331,12 +1331,12 @@ out: char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *dev = NULL; char *ret = NULL; int rc; - rc = libxl__device_disk_set_backend(&gc, disk); + rc = libxl__device_disk_set_backend(gc, disk); if (rc) goto out; switch (disk->backend) { @@ -1355,7 +1355,7 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) dev = disk->pdev_path; break; case LIBXL_DISK_FORMAT_VHD: - dev = libxl__blktap_devpath(&gc, disk->pdev_path, + dev = libxl__blktap_devpath(gc, disk->pdev_path, disk->format); break; case LIBXL_DISK_FORMAT_QCOW: @@ -1386,7 +1386,7 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) out: if (dev != NULL) ret = strdup(dev); - libxl__free_all(&gc); + GC_FREE; return ret; } @@ -1448,7 +1448,7 @@ static int libxl__device_from_nic(libxl__gc *gc, uint32_t domid, int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); flexarray_t *front; flexarray_t *back; libxl__device device; @@ -1467,59 +1467,59 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) } if (nic->devid == -1) { - if (!(dompath = libxl__xs_get_dompath(&gc, domid))) { + if (!(dompath = libxl__xs_get_dompath(gc, domid))) { rc = ERROR_FAIL; goto out_free; } - if (!(l = libxl__xs_directory(&gc, XBT_NULL, - libxl__sprintf(&gc, "%s/device/vif", dompath), &nb))) { + if (!(l = libxl__xs_directory(gc, XBT_NULL, + libxl__sprintf(gc, "%s/device/vif", dompath), &nb))) { nic->devid = 0; } else { nic->devid = strtoul(l[nb - 1], NULL, 10) + 1; } } - rc = libxl__device_from_nic(&gc, domid, nic, &device); + rc = libxl__device_from_nic(gc, domid, nic, &device); if ( rc != 0 ) goto out_free; flexarray_append(back, "frontend-id"); - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); flexarray_append(back, "online"); flexarray_append(back, "1"); flexarray_append(back, "state"); - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); if (nic->script) { flexarray_append(back, "script"); flexarray_append(back, nic->script[0]==''/'' ? nic->script - : libxl__sprintf(&gc, "%s/%s", + : libxl__sprintf(gc, "%s/%s", libxl_xen_script_dir_path(), nic->script)); } flexarray_append(back, "mac"); - flexarray_append(back,libxl__sprintf(&gc, + flexarray_append(back,libxl__sprintf(gc, LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); if (nic->ip) { flexarray_append(back, "ip"); - flexarray_append(back, libxl__strdup(&gc, nic->ip)); + flexarray_append(back, libxl__strdup(gc, nic->ip)); } flexarray_append(back, "bridge"); - flexarray_append(back, libxl__strdup(&gc, nic->bridge)); + flexarray_append(back, libxl__strdup(gc, nic->bridge)); flexarray_append(back, "handle"); - flexarray_append(back, libxl__sprintf(&gc, "%d", nic->devid)); + flexarray_append(back, libxl__sprintf(gc, "%d", nic->devid)); flexarray_append(front, "backend-id"); - flexarray_append(front, libxl__sprintf(&gc, "%d", nic->backend_domid)); + flexarray_append(front, libxl__sprintf(gc, "%d", nic->backend_domid)); flexarray_append(front, "state"); - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); flexarray_append(front, "handle"); - flexarray_append(front, libxl__sprintf(&gc, "%d", nic->devid)); + flexarray_append(front, libxl__sprintf(gc, "%d", nic->devid)); flexarray_append(front, "mac"); - flexarray_append(front, libxl__sprintf(&gc, + flexarray_append(front, libxl__sprintf(gc, LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); - libxl__device_generic_add(&gc, &device, - libxl__xs_kvs_of_flexarray(&gc, back, back->count), - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); + libxl__device_generic_add(gc, &device, + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count)); /* FIXME: wait for plug */ rc = 0; @@ -1527,39 +1527,39 @@ out_free: flexarray_free(back); flexarray_free(front); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_nic(&gc, domid, nic, &device); + rc = libxl__device_from_nic(gc, domid, nic, &device); if (rc != 0) goto out; - rc = libxl__device_remove(&gc, &device, 1); + rc = libxl__device_remove(gc, &device, 1); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_nic(&gc, domid, nic, &device); + rc = libxl__device_from_nic(gc, domid, nic, &device); if (rc != 0) goto out; - rc = libxl__device_destroy(&gc, &device); + rc = libxl__device_destroy(gc, &device); out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1607,26 +1607,26 @@ static void libxl__device_nic_from_xs_be(libxl__gc *gc, int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid, int devid, libxl_device_nic *nic) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *dompath, *path; int rc = ERROR_FAIL; memset(nic, 0, sizeof (libxl_device_nic)); - dompath = libxl__xs_get_dompath(&gc, domid); + dompath = libxl__xs_get_dompath(gc, domid); if (!dompath) goto out; - path = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, "%s/device/vif/%d/backend", + path = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%s/device/vif/%d/backend", dompath, devid)); if (!path) goto out; - libxl__device_nic_from_xs_be(&gc, path, nic); + libxl__device_nic_from_xs_be(gc, path, nic); rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1665,16 +1665,16 @@ static int libxl__append_nic_list_of_type(libxl__gc *gc, libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int *num) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl_device_nic *nics = NULL; int rc; *num = 0; - rc = libxl__append_nic_list_of_type(&gc, domid, "vif", &nics, num); + rc = libxl__append_nic_list_of_type(gc, domid, "vif", &nics, num); if (rc) goto out_err; - libxl__free_all(&gc); + GC_FREE; return nics; out_err: @@ -1690,36 +1690,36 @@ out_err: int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic, libxl_nicinfo *nicinfo) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *dompath, *nicpath; char *val; - dompath = libxl__xs_get_dompath(&gc, domid); + dompath = libxl__xs_get_dompath(gc, domid); nicinfo->devid = nic->devid; - nicpath = libxl__sprintf(&gc, "%s/device/vif/%d", dompath, nicinfo->devid); + nicpath = libxl__sprintf(gc, "%s/device/vif/%d", dompath, nicinfo->devid); nicinfo->backend = xs_read(ctx->xsh, XBT_NULL, - libxl__sprintf(&gc, "%s/backend", nicpath), NULL); + libxl__sprintf(gc, "%s/backend", nicpath), NULL); if (!nicinfo->backend) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", nicpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend-id", nicpath)); nicinfo->backend_id = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", nicpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/state", nicpath)); nicinfo->state = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", nicpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/event-channel", nicpath)); nicinfo->evtch = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/tx-ring-ref", nicpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/tx-ring-ref", nicpath)); nicinfo->rref_tx = val ? strtoul(val, NULL, 10) : -1; - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/rx-ring-ref", nicpath)); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/rx-ring-ref", nicpath)); nicinfo->rref_rx = val ? strtoul(val, NULL, 10) : -1; nicinfo->frontend = xs_read(ctx->xsh, XBT_NULL, - libxl__sprintf(&gc, "%s/frontend", nicinfo->backend), NULL); - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", nicinfo->backend)); + libxl__sprintf(gc, "%s/frontend", nicinfo->backend), NULL); + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/frontend-id", nicinfo->backend)); nicinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1; - libxl__free_all(&gc); + GC_FREE; return 0; } @@ -1825,7 +1825,7 @@ static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid, int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); flexarray_t *front; flexarray_t *back; libxl__device device; @@ -1842,64 +1842,64 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) goto out_free; } - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); + rc = libxl__device_from_vkb(gc, domid, vkb, &device); if (rc != 0) goto out_free; flexarray_append(back, "frontend-id"); - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); flexarray_append(back, "online"); flexarray_append(back, "1"); flexarray_append(back, "state"); - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); flexarray_append(back, "domain"); - flexarray_append(back, libxl__domid_to_name(&gc, domid)); + flexarray_append(back, libxl__domid_to_name(gc, domid)); flexarray_append(front, "backend-id"); - flexarray_append(front, libxl__sprintf(&gc, "%d", vkb->backend_domid)); + flexarray_append(front, libxl__sprintf(gc, "%d", vkb->backend_domid)); flexarray_append(front, "state"); - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); - libxl__device_generic_add(&gc, &device, - libxl__xs_kvs_of_flexarray(&gc, back, back->count), - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); + libxl__device_generic_add(gc, &device, + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count)); rc = 0; out_free: flexarray_free(back); flexarray_free(front); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); + rc = libxl__device_from_vkb(gc, domid, vkb, &device); if (rc != 0) goto out; - rc = libxl__device_remove(&gc, &device, 1); + rc = libxl__device_remove(gc, &device, 1); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); + rc = libxl__device_from_vkb(gc, domid, vkb, &device); if (rc != 0) goto out; - rc = libxl__device_destroy(&gc, &device); + rc = libxl__device_destroy(gc, &device); out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1935,7 +1935,7 @@ static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid, int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); flexarray_t *front; flexarray_t *back; libxl__device device; @@ -1952,20 +1952,20 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) goto out_free; } - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); + rc = libxl__device_from_vfb(gc, domid, vfb, &device); if (rc != 0) goto out_free; - flexarray_append_pair(back, "frontend-id", libxl__sprintf(&gc, "%d", domid)); + flexarray_append_pair(back, "frontend-id", libxl__sprintf(gc, "%d", domid)); flexarray_append_pair(back, "online", "1"); - flexarray_append_pair(back, "state", libxl__sprintf(&gc, "%d", 1)); - flexarray_append_pair(back, "domain", libxl__domid_to_name(&gc, domid)); - flexarray_append_pair(back, "vnc", libxl__sprintf(&gc, "%d", vfb->vnc)); + flexarray_append_pair(back, "state", libxl__sprintf(gc, "%d", 1)); + flexarray_append_pair(back, "domain", libxl__domid_to_name(gc, domid)); + flexarray_append_pair(back, "vnc", libxl__sprintf(gc, "%d", vfb->vnc)); flexarray_append_pair(back, "vnclisten", vfb->vnclisten); flexarray_append_pair(back, "vncpasswd", vfb->vncpasswd); - flexarray_append_pair(back, "vncdisplay", libxl__sprintf(&gc, "%d", vfb->vncdisplay)); - flexarray_append_pair(back, "vncunused", libxl__sprintf(&gc, "%d", vfb->vncunused)); - flexarray_append_pair(back, "sdl", libxl__sprintf(&gc, "%d", vfb->sdl)); - flexarray_append_pair(back, "opengl", libxl__sprintf(&gc, "%d", vfb->opengl)); + flexarray_append_pair(back, "vncdisplay", libxl__sprintf(gc, "%d", vfb->vncdisplay)); + flexarray_append_pair(back, "vncunused", libxl__sprintf(gc, "%d", vfb->vncunused)); + flexarray_append_pair(back, "sdl", libxl__sprintf(gc, "%d", vfb->sdl)); + flexarray_append_pair(back, "opengl", libxl__sprintf(gc, "%d", vfb->opengl)); if (vfb->xauthority) { flexarray_append_pair(back, "xauthority", vfb->xauthority); } @@ -1973,50 +1973,50 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) flexarray_append_pair(back, "display", vfb->display); } - flexarray_append_pair(front, "backend-id", libxl__sprintf(&gc, "%d", vfb->backend_domid)); - flexarray_append_pair(front, "state", libxl__sprintf(&gc, "%d", 1)); + flexarray_append_pair(front, "backend-id", libxl__sprintf(gc, "%d", vfb->backend_domid)); + flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1)); - libxl__device_generic_add(&gc, &device, - libxl__xs_kvs_of_flexarray(&gc, back, back->count), - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); + libxl__device_generic_add(gc, &device, + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count)); rc = 0; out_free: flexarray_free(front); flexarray_free(back); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); + rc = libxl__device_from_vfb(gc, domid, vfb, &device); if (rc != 0) goto out; - rc = libxl__device_remove(&gc, &device, 1); + rc = libxl__device_remove(gc, &device, 1); out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl__device device; int rc; - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); + rc = libxl__device_from_vfb(gc, domid, vfb, &device); if (rc != 0) goto out; - rc = libxl__device_destroy(&gc, &device); + rc = libxl__device_destroy(gc, &device); out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2024,13 +2024,13 @@ out: int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *mem, *endptr; uint32_t memorykb; - char *dompath = libxl__xs_get_dompath(&gc, domid); + char *dompath = libxl__xs_get_dompath(gc, domid); int rc = 1; - mem = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/memory/target", dompath)); + mem = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/memory/target", dompath)); if (!mem) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot get memory info from %s/memory/target\n", dompath); goto out; @@ -2055,7 +2055,7 @@ int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb) rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2163,12 +2163,12 @@ retry: int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid, int32_t target_memkb, int relative, int enforce) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc = 1, abort = 0; uint32_t memorykb = 0, videoram = 0; uint32_t current_target_memkb = 0, new_target_memkb = 0; char *memmax, *endptr, *videoram_s = NULL, *target = NULL; - char *dompath = libxl__xs_get_dompath(&gc, domid); + char *dompath = libxl__xs_get_dompath(gc, domid); xc_domaininfo_t info; libxl_dominfo ptr; char *uuid; @@ -2177,11 +2177,11 @@ int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid, retry_transaction: t = xs_transaction_start(ctx->xsh); - target = libxl__xs_read(&gc, t, libxl__sprintf(&gc, + target = libxl__xs_read(gc, t, libxl__sprintf(gc, "%s/memory/target", dompath)); if (!target && !domid) { xs_transaction_end(ctx->xsh, t, 1); - rc = libxl__fill_dom0_memory_info(&gc, ¤t_target_memkb); + rc = libxl__fill_dom0_memory_info(gc, ¤t_target_memkb); if (rc < 0) { abort = 1; goto out; @@ -2203,7 +2203,7 @@ retry_transaction: goto out; } } - memmax = libxl__xs_read(&gc, t, libxl__sprintf(&gc, + memmax = libxl__xs_read(gc, t, libxl__sprintf(gc, "%s/memory/static-max", dompath)); if (!memmax) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, @@ -2243,7 +2243,7 @@ retry_transaction: abort = 1; goto out; } - videoram_s = libxl__xs_read(&gc, t, libxl__sprintf(&gc, + videoram_s = libxl__xs_read(gc, t, libxl__sprintf(gc, "%s/memory/videoram", dompath)); videoram = videoram_s ? atoi(videoram_s) : 0; @@ -2272,7 +2272,7 @@ retry_transaction: goto out; } - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/memory/target", + libxl__xs_write(gc, t, libxl__sprintf(gc, "%s/memory/target", dompath), "%"PRIu32, new_target_memkb); rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info); if (rc != 1 || info.domain != domid) { @@ -2280,8 +2280,8 @@ retry_transaction: goto out; } xcinfo2xlinfo(&info, &ptr); - uuid = libxl__uuid2string(&gc, ptr.uuid); - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/vm/%s/memory", uuid), + uuid = libxl__uuid2string(gc, ptr.uuid); + libxl__xs_write(gc, t, libxl__sprintf(gc, "/vm/%s/memory", uuid), "%"PRIu32, new_target_memkb / 1024); out: @@ -2289,22 +2289,22 @@ out: if (errno == EAGAIN) goto retry_transaction; - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc = 1; char *target = NULL, *endptr = NULL; - char *dompath = libxl__xs_get_dompath(&gc, domid); + char *dompath = libxl__xs_get_dompath(gc, domid); uint32_t target_memkb; - target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, + target = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/memory/target", dompath)); if (!target && !domid) { - rc = libxl__fill_dom0_memory_info(&gc, &target_memkb); + rc = libxl__fill_dom0_memory_info(gc, &target_memkb); if (rc < 0) goto out; } else if (!target) { @@ -2325,14 +2325,14 @@ int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info, libxl_device_model_info *dm_info, uint32_t *need_memkb) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc = ERROR_INVAL; *need_memkb = b_info->target_memkb; switch (b_info->type) { @@ -2351,7 +2351,7 @@ int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info, *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024)); rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2361,12 +2361,12 @@ int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb) int rc = 0; libxl_physinfo info; uint32_t freemem_slack; - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); rc = libxl_get_physinfo(ctx, &info); if (rc < 0) goto out; - rc = libxl__get_free_memory_slack(&gc, &freemem_slack); + rc = libxl__get_free_memory_slack(gc, &freemem_slack); if (rc < 0) goto out; @@ -2376,7 +2376,7 @@ int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb) *memkb = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2386,9 +2386,9 @@ int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t int rc = 0; libxl_physinfo info; uint32_t freemem_slack; - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); - rc = libxl__get_free_memory_slack(&gc, &freemem_slack); + rc = libxl__get_free_memory_slack(gc, &freemem_slack); if (rc < 0) goto out; while (wait_secs > 0) { @@ -2405,7 +2405,7 @@ int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t rc = ERROR_NOMEM; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2631,7 +2631,7 @@ int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid, int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_cpumap *cpumap) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl_dominfo info; char *dompath; xs_transaction_t t; @@ -2641,14 +2641,14 @@ int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_cpumap *cpumap) LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list"); goto out; } - if (!(dompath = libxl__xs_get_dompath(&gc, domid))) + if (!(dompath = libxl__xs_get_dompath(gc, domid))) goto out; retry_transaction: t = xs_transaction_start(ctx->xsh); for (i = 0; i <= info.vcpu_max_id; i++) - libxl__xs_write(&gc, t, - libxl__sprintf(&gc, "%s/cpu/%u/availability", dompath, i), + libxl__xs_write(gc, t, + libxl__sprintf(gc, "%s/cpu/%u/availability", dompath, i), "%s", libxl_cpumap_test(cpumap, i) ? "online" : "offline"); if (!xs_transaction_end(ctx->xsh, t, 0)) { if (errno == EAGAIN) @@ -2656,7 +2656,7 @@ retry_transaction: } else rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -2776,12 +2776,12 @@ int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, char *trigger_name, uint3 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq) { - libxl__gc gc = LIBXL_INIT_GC(ctx); - char *dompath = libxl__xs_get_dompath(&gc, domid); + GC_INIT(ctx); + char *dompath = libxl__xs_get_dompath(gc, domid); - libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/control/sysrq", dompath), "%c", sysrq); + libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/control/sysrq", dompath), "%c", sysrq); - libxl__free_all(&gc); + GC_FREE; return 0; } @@ -2868,15 +2868,15 @@ void libxl_xen_console_read_finish(libxl_ctx *ctx, uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); - char *dompath = libxl__xs_get_dompath(&gc, domid); + GC_INIT(ctx); + char *dompath = libxl__xs_get_dompath(gc, domid); char *vm_path, *start_time; uint32_t ret; vm_path = libxl__xs_read( - &gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dompath)); + gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dompath)); start_time = libxl__xs_read( - &gc, XBT_NULL, libxl__sprintf(&gc, "%s/start_time", vm_path)); + gc, XBT_NULL, libxl__sprintf(gc, "%s/start_time", vm_path)); if (start_time == NULL) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1, "Can''t get start time of domain ''%d''", domid); @@ -2884,7 +2884,7 @@ uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid) }else{ ret = strtoul(start_time, NULL, 10); } - libxl__free_all(&gc); + GC_FREE; return ret; } @@ -3037,15 +3037,15 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, libxl_cpumap cpumap, libxl_uuid *uuid, uint32_t *poolid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; int i; xs_transaction_t t; char *uuid_string; - uuid_string = libxl__uuid2string(&gc, *uuid); + uuid_string = libxl__uuid2string(gc, *uuid); if (!uuid_string) { - libxl__free_all(&gc); + GC_FREE; return ERROR_NOMEM; } @@ -3053,7 +3053,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, if (rc) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "Could not create cpupool"); - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } @@ -3064,7 +3064,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "Error moving cpu to cpupool"); libxl_cpupool_destroy(ctx, *poolid); - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } } @@ -3072,16 +3072,16 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, for (;;) { t = xs_transaction_start(ctx->xsh); - xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/pool/%d", *poolid)); - libxl__xs_write(&gc, t, - libxl__sprintf(&gc, "/local/pool/%d/uuid", *poolid), + xs_mkdir(ctx->xsh, t, libxl__sprintf(gc, "/local/pool/%d", *poolid)); + libxl__xs_write(gc, t, + libxl__sprintf(gc, "/local/pool/%d/uuid", *poolid), "%s", uuid_string); - libxl__xs_write(&gc, t, - libxl__sprintf(&gc, "/local/pool/%d/name", *poolid), + libxl__xs_write(gc, t, + libxl__sprintf(gc, "/local/pool/%d/name", *poolid), "%s", name); if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) { - libxl__free_all(&gc); + GC_FREE; return 0; } } @@ -3089,7 +3089,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc, i; xc_cpupoolinfo_t *info; xs_transaction_t t; @@ -3097,7 +3097,7 @@ int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) info = xc_cpupool_getinfo(ctx->xch, poolid); if (info == NULL) { - libxl__free_all(&gc); + GC_FREE; return ERROR_NOMEM; } @@ -3131,7 +3131,7 @@ int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) for (;;) { t = xs_transaction_start(ctx->xsh); - xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/pool/%d", poolid)); + xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "/local/pool/%d", poolid)); if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) break; @@ -3143,21 +3143,21 @@ out1: libxl_cpumap_dispose(&cpumap); out: xc_cpupool_infofree(ctx->xch, info); - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); xs_transaction_t t; xc_cpupoolinfo_t *info; int rc; info = xc_cpupool_getinfo(ctx->xch, poolid); if (info == NULL) { - libxl__free_all(&gc); + GC_FREE; return ERROR_NOMEM; } @@ -3170,8 +3170,8 @@ int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) for (;;) { t = xs_transaction_start(ctx->xsh); - libxl__xs_write(&gc, t, - libxl__sprintf(&gc, "/local/pool/%d/name", poolid), + libxl__xs_write(gc, t, + libxl__sprintf(gc, "/local/pool/%d/name", poolid), "%s", name); if (xs_transaction_end(ctx->xsh, t, 0)) @@ -3186,7 +3186,7 @@ int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) out: xc_cpupool_infofree(ctx->xch, info); - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -3293,16 +3293,16 @@ out: int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; char *dom_path; char *vm_path; char *poolname; xs_transaction_t t; - dom_path = libxl__xs_get_dompath(&gc, domid); + dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } @@ -3310,26 +3310,26 @@ int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid) if (rc) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "Error moving domain to cpupool"); - libxl__free_all(&gc); + GC_FREE; return ERROR_FAIL; } for (;;) { t = xs_transaction_start(ctx->xsh); - poolname = libxl__cpupoolid_to_name(&gc, poolid); - vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path)); + poolname = libxl__cpupoolid_to_name(gc, poolid); + vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dom_path)); if (!vm_path) break; - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), + libxl__xs_write(gc, t, libxl__sprintf(gc, "%s/pool_name", vm_path), "%s", poolname); if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) break; } - libxl__free_all(&gc); + GC_FREE; return 0; } diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c index b8399a1..ce83b8e 100644 --- a/tools/libxl/libxl_bootloader.c +++ b/tools/libxl/libxl_bootloader.c @@ -328,7 +328,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, libxl_device_disk *disk, uint32_t domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int ret, rc = 0; char *fifo = NULL; char *diskpath = NULL; @@ -388,7 +388,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, goto out_close; } - args = make_bootloader_args(&gc, info, domid, fifo, diskpath); + args = make_bootloader_args(gc, info, domid, fifo, diskpath); if (args == NULL) { rc = ERROR_NOMEM; goto out_close; @@ -411,8 +411,8 @@ int libxl_run_bootloader(libxl_ctx *ctx, goto out_close; } - dom_console_xs_path = libxl__sprintf(&gc, "%s/console/tty", libxl__xs_get_dompath(&gc, domid)); - libxl__xs_write(&gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path); + dom_console_xs_path = libxl__sprintf(gc, "%s/console/tty", libxl__xs_get_dompath(gc, domid)); + libxl__xs_write(gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path); pid = fork_exec_bootloader(&bootloader_fd, info->u.pv.bootloader, args); if (pid < 0) { @@ -435,7 +435,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, fcntl(fifo_fd, F_SETFL, O_NDELAY); - blout = bootloader_interact(&gc, xenconsoled_fd, bootloader_fd, fifo_fd); + blout = bootloader_interact(gc, xenconsoled_fd, bootloader_fd, fifo_fd); if (blout == NULL) { goto out_close; } @@ -445,7 +445,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, goto out_close; } - parse_bootloader_result(&gc, info, blout); + parse_bootloader_result(gc, info, blout); rc = 0; out_close: @@ -472,7 +472,7 @@ out_close: free(args); out: - libxl__free_all(&gc); + GC_FREE; return rc; } diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index ccb56c7..69f10fe 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -670,20 +670,20 @@ error_out: int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config, libxl_console_ready cb, void *priv, uint32_t *domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = do_domain_create(&gc, d_config, cb, priv, domid, -1); - libxl__free_all(&gc); + rc = do_domain_create(gc, d_config, cb, priv, domid, -1); + GC_FREE; return rc; } int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = do_domain_create(&gc, d_config, cb, priv, domid, restore_fd); - libxl__free_all(&gc); + rc = do_domain_create(gc, d_config, cb, priv, domid, restore_fd); + GC_FREE; return rc; } diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 96098de..b1ff967 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -730,7 +730,7 @@ int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid, const char *userdata_userid, const uint8_t *data, int datalen) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); const char *filename; const char *newfilename; int e, rc; @@ -738,18 +738,18 @@ int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid, FILE *f = NULL; size_t rs; - filename = userdata_path(&gc, domid, userdata_userid, "d"); + filename = userdata_path(gc, domid, userdata_userid, "d"); if (!filename) { rc = ERROR_NOMEM; goto out; } if (!datalen) { - rc = userdata_delete(&gc, filename); + rc = userdata_delete(gc, filename); goto out; } - newfilename = userdata_path(&gc, domid, userdata_userid, "n"); + newfilename = userdata_path(gc, domid, userdata_userid, "n"); if (!newfilename) { rc = ERROR_NOMEM; goto out; @@ -791,7 +791,7 @@ err: LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot write %s for %s", newfilename, filename); out: - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -799,13 +799,13 @@ int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid, const char *userdata_userid, uint8_t **data_r, int *datalen_r) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); const char *filename; int e, rc; int datalen = 0; void *data = 0; - filename = userdata_path(&gc, domid, userdata_userid, "d"); + filename = userdata_path(gc, domid, userdata_userid, "d"); if (!filename) { rc = ERROR_NOMEM; goto out; @@ -827,7 +827,7 @@ int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid, if (datalen_r) *datalen_r = datalen; rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index 63c3050..120c239 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -483,7 +483,7 @@ static int is_assigned(libxl_device_pci *assigned, int num_assigned, libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); libxl_device_pci *pcidevs = NULL, *new, *assigned; struct dirent *de; DIR *dir; @@ -491,7 +491,7 @@ libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) *num = 0; - rc = get_all_assigned_devices(&gc, &assigned, &num_assigned); + rc = get_all_assigned_devices(gc, &assigned, &num_assigned); if ( rc ) goto out; @@ -528,7 +528,7 @@ libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) out_closedir: closedir(dir); out: - libxl__free_all(&gc); + GC_FREE; return pcidevs; } @@ -782,10 +782,10 @@ static int libxl__device_pci_reset(libxl__gc *gc, unsigned int domain, unsigned int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = libxl__device_pci_add(&gc, domid, pcidev, 0); - libxl__free_all(&gc); + rc = libxl__device_pci_add(gc, domid, pcidev, 0); + GC_FREE; return rc; } @@ -1057,24 +1057,24 @@ out: int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = libxl__device_pci_remove_common(&gc, domid, pcidev, 0); + rc = libxl__device_pci_remove_common(gc, domid, pcidev, 0); - libxl__free_all(&gc); + GC_FREE; return rc; } int libxl_device_pci_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); int rc; - rc = libxl__device_pci_remove_common(&gc, domid, pcidev, 1); + rc = libxl__device_pci_remove_common(gc, domid, pcidev, 1); - libxl__free_all(&gc); + GC_FREE; return rc; } @@ -1115,15 +1115,15 @@ static void libxl__device_pci_from_xs_be(libxl__gc *gc, libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int *num) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *be_path, *num_devs; int n, i; libxl_device_pci *pcidevs = NULL; *num = 0; - be_path = libxl__sprintf(&gc, "%s/backend/pci/%d/0", libxl__xs_get_dompath(&gc, 0), domid); - num_devs = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/num_devs", be_path)); + be_path = libxl__sprintf(gc, "%s/backend/pci/%d/0", libxl__xs_get_dompath(gc, 0), domid); + num_devs = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/num_devs", be_path)); if (!num_devs) goto out; @@ -1131,11 +1131,11 @@ libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int *num pcidevs = calloc(n, sizeof(libxl_device_pci)); for (i = 0; i < n; i++) - libxl__device_pci_from_xs_be(&gc, be_path, pcidevs + i, i); + libxl__device_pci_from_xs_be(gc, be_path, pcidevs + i, i); *num = n; out: - libxl__free_all(&gc); + GC_FREE; return pcidevs; } diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c index c7696d7..60af98c 100644 --- a/tools/libxl/libxl_qmp.c +++ b/tools/libxl/libxl_qmp.c @@ -94,7 +94,7 @@ static int store_serial_port_info(libxl__qmp_handler *qmp, const char *chardev, int port) { - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); + GC_INIT(qmp->ctx); char *path = NULL; int ret = 0; @@ -102,12 +102,12 @@ static int store_serial_port_info(libxl__qmp_handler *qmp, return 0; } - path = libxl__xs_get_dompath(&gc, qmp->domid); - path = libxl__sprintf(&gc, "%s/serial/%d/tty", path, port); + 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); + ret = libxl__xs_write(gc, XBT_NULL, path, "%s", chardev + 4); - libxl__free_all(&gc); + GC_FREE; return ret; } @@ -521,7 +521,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, { int id = 0; int ret = 0; - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); + GC_INIT(qmp->ctx); qmp_request_context context = { .rc = 0 }; id = qmp_send(qmp, cmd, args, callback, opaque, &context); @@ -531,7 +531,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, qmp->wait_for_id = id; while (qmp->wait_for_id == id) { - if ((ret = qmp_next(&gc, qmp)) < 0) { + if ((ret = qmp_next(gc, qmp)) < 0) { break; } } @@ -540,7 +540,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, ret = context.rc; } - libxl__free_all(&gc); + GC_FREE; return ret; } @@ -559,15 +559,15 @@ 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); + GC_INIT(ctx); qmp = qmp_init_handler(ctx, domid); - qmp_socket = libxl__sprintf(&gc, "%s/qmp-libxl-%d", + 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); + GC_FREE; qmp_free_handler(qmp); return NULL; } @@ -576,12 +576,12 @@ libxl__qmp_handler *libxl__qmp_initialize(libxl_ctx *ctx, uint32_t domid) /* Wait for the response to qmp_capabilities */ while (!qmp->connected) { - if ((ret = qmp_next(&gc, qmp)) < 0) { + if ((ret = qmp_next(gc, qmp)) < 0) { break; } } - libxl__free_all(&gc); + GC_FREE; if (!qmp->connected) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to connect to QMP"); libxl__qmp_close(qmp); @@ -626,9 +626,9 @@ static int pci_add_callback(libxl__qmp_handler *qmp, { libxl_device_pci *pcidev = opaque; const libxl__json_object *bus = NULL; - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); + GC_INIT(qmp->ctx); int i, j, rc = -1; - char *asked_id = libxl__sprintf(&gc, PCI_PT_QDEV_ID, + char *asked_id = libxl__sprintf(gc, PCI_PT_QDEV_ID, pcidev->bus, pcidev->dev, pcidev->func); for (i = 0; (bus = libxl__json_array_get(response, i)); i++) { @@ -665,7 +665,7 @@ static int pci_add_callback(libxl__qmp_handler *qmp, out: - libxl__free_all(&gc); + GC_FREE; return rc; } diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index f1f2a6d..d36c737 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -186,29 +186,29 @@ char *libxl_schedid_to_name(libxl_ctx *ctx, int schedid) int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char * stubdom_id_s; int ret; - stubdom_id_s = libxl__xs_read(&gc, XBT_NULL, - libxl__sprintf(&gc, "%s/image/device-model-domid", - libxl__xs_get_dompath(&gc, guest_domid))); + stubdom_id_s = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%s/image/device-model-domid", + libxl__xs_get_dompath(gc, guest_domid))); if (stubdom_id_s) ret = atoi(stubdom_id_s); else ret = 0; - libxl__free_all(&gc); + GC_FREE; return ret; } int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); char *target, *endptr; uint32_t value; int ret = 0; - target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid))); + target = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/target", libxl__xs_get_dompath(gc, domid))); if (!target) goto out; value = strtol(target, &endptr, 10); @@ -218,7 +218,7 @@ int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid) *target_domid = value; ret = 1; out: - libxl__free_all(&gc); + GC_FREE; return ret; } @@ -240,27 +240,27 @@ static int logrename(libxl__gc *gc, const char *old, const char *new) int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name) { - libxl__gc gc = LIBXL_INIT_GC(ctx); + GC_INIT(ctx); struct stat stat_buf; char *logfile, *logfile_new; int i, rc; - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name); + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log", name); if (stat(logfile, &stat_buf) == 0) { /* file exists, rotate */ - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.10", name); + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log.10", name); unlink(logfile); for (i = 9; i > 0; i--) { - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i); - logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i + 1); - rc = logrename(&gc, logfile, logfile_new); + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log.%d", name, i); + logfile_new = libxl__sprintf(gc, "/var/log/xen/%s.log.%d", name, i + 1); + rc = logrename(gc, logfile, logfile_new); if (rc) goto out; } - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name); - logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.1", name); + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log", name); + logfile_new = libxl__sprintf(gc, "/var/log/xen/%s.log.1", name); - rc = logrename(&gc, logfile, logfile_new); + rc = logrename(gc, logfile, logfile_new); if (rc) goto out; } else { @@ -272,7 +272,7 @@ int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name) *full_name = strdup(logfile); rc = 0; out: - libxl__free_all(&gc); + GC_FREE; return rc; } -- 1.7.2.5
Ian Jackson
2011-Dec-05 18:10 UTC
[PATCH 13/15] libxl: make LIBXL_INIT_GC a statement, not an initialiser
Previously LIBXL_INIT_GC was an initialiser, which you were expected to use like this: libxl__gc gc = LIBXL_INIT_GC(ctx); But we are going to want to put things in the gc which are to be initialised using other macros. That means that LIBXL_INIT_GC has to become a statement too. So instead, we make it so that it''s used like this: libxl_gc gc; LIBXL_INIT_GC(gc,ctx); In fact there is only one caller now, GC_INIT, which uses this trick: libxl_gc gc[1]; LIBXL_INIT_GC(gc[0],ctx); Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/libxl_internal.h | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 1d1dc35..d015c7c 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -145,7 +145,12 @@ typedef struct { libxl_ctx *owner; } libxl__gc; -#define LIBXL_INIT_GC(ctx) (libxl__gc){ .alloc_maxsize = 0, .alloc_ptrs = 0, .owner = ctx } +#define LIBXL_INIT_GC(gc,ctx) do{ \ + (gc).alloc_maxsize = 0; \ + (gc).alloc_ptrs = 0; \ + (gc).owner = (ctx); \ + } while(0) + static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) { return gc->owner; @@ -676,7 +681,7 @@ libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); * as a local variable. */ -#define GC_INIT(ctx) libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) } +#define GC_INIT(ctx) libxl__gc gc[1]; LIBXL_INIT_GC(gc[0],ctx) #define GC_FREE libxl__free_all(gc) #define CTX libxl__gc_owner(gc) -- 1.7.2.5
Ian Jackson
2011-Dec-05 18:10 UTC
[PATCH 14/15] libxl: New API for providing OS events to libxl
We provide a new set of functions and related structures libxl_osevent_* which are to be used by event-driven applications to receive information from libxl about which fds libxl is interested in, and what timeouts libxl is waiting for, and to pass back to libxl information about which fds are readable/writeable etc., and which timeouts have occurred. Ie, low-level events. In this patch, this new machinery is still all unused. Callers will appear in the next patch in the series, which introduces a new API for applications to receive high-level events about actual domains etc. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/Makefile | 2 +- tools/libxl/libxl.c | 25 ++ tools/libxl/libxl.h | 6 + tools/libxl/libxl_event.c | 711 ++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_event.h | 199 ++++++++++++ tools/libxl/libxl_internal.h | 216 +++++++++++++- 6 files changed, 1155 insertions(+), 4 deletions(-) create mode 100644 tools/libxl/libxl_event.c create mode 100644 tools/libxl/libxl_event.h diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index 4e0f3fb..3d575b8 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -38,7 +38,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_qmp.o $(LIBXL_OBJS-y) + libxl_qmp.o libxl_event.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 3a8cfe3..58f280c 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -60,6 +60,16 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, * only as an initialiser, not as an expression. */ memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); + ctx->osevent_hooks = 0; + + ctx->fd_beforepolled = 0; + LIBXL_LIST_INIT(&ctx->efds); + LIBXL_TAILQ_INIT(&ctx->etimes); + + ctx->watch_slots = 0; + LIBXL_SLIST_INIT(&ctx->watch_freeslots); + libxl__ev_fd_init(&ctx->watch_efd); + if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" "failed to stat %s", XENSTORE_PID_FILE); @@ -89,10 +99,25 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, int libxl_ctx_free(libxl_ctx *ctx) { + int i; + GC_INIT(ctx); + if (!ctx) return 0; + + for (i = 0; i < ctx->watch_nslots; i++) + assert(!libxl__watch_slot_contents(gc, i)); + libxl__ev_fd_deregister(gc, &ctx->watch_efd); + + assert(LIBXL_LIST_EMPTY(&ctx->efds)); + assert(LIBXL_TAILQ_EMPTY(&ctx->etimes)); + if (ctx->xch) xc_interface_close(ctx->xch); libxl_version_info_dispose(&ctx->version_info); if (ctx->xsh) xs_daemon_close(ctx->xsh); + + free(ctx->fd_beforepolled); + free(ctx->watch_slots); + return 0; } diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 289dc85..654a5b0 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -137,6 +137,7 @@ #include <xen/sysctl.h> #include <libxl_uuid.h> +#include <_libxl_list.h> typedef uint8_t libxl_mac[6]; #define LIBXL_MAC_FMT "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx" @@ -222,6 +223,9 @@ enum { ERROR_BADFAIL = -7, ERROR_GUEST_TIMEDOUT = -8, ERROR_TIMEDOUT = -9, + ERROR_NOT_READY = -10, + ERROR_OSEVENT_REG_FAIL = -11, + ERROR_BUFFERFULL = -12, }; #define LIBXL_VERSION 0 @@ -635,6 +639,8 @@ const char *libxl_lock_dir_path(void); const char *libxl_run_dir_path(void); const char *libxl_xenpaging_dir_path(void); +#include <libxl_event.h> + #endif /* LIBXL_H */ /* diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c new file mode 100644 index 0000000..8d4dbf6 --- /dev/null +++ b/tools/libxl/libxl_event.c @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2011 Citrix Ltd. + * + * 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. + */ +/* + * Internal event machinery for use by other parts of libxl + */ + +#include <poll.h> + +#include "libxl_internal.h" + +/* + * The counter osevent_in_hook is used to ensure that the application + * honours the reentrancy restriction documented in libxl_event.h. + * + * The application''s registration hooks should be called ONLY via + * these macros, with the ctx locked. Likewise all the "occurred" + * entrypoints from the application should assert(!in_hook); + */ +#define OSEVENT_HOOK_INTERN(defval, hookname, ...) \ + (CTX->osevent_hooks \ + ? (CTX->osevent_in_hook++, \ + CTX->osevent_hooks->hookname(CTX->osevent_user, __VA_ARGS__), \ + CTX->osevent_in_hook--) \ + : defval) + +#define OSEVENT_HOOK(hookname,...) \ + OSEVENT_HOOK_INTERN(0, hookname, __VA_ARGS__) + +#define OSEVENT_HOOK_VOID(hookname,...) \ + OSEVENT_HOOK_INTERN((void)0, hookname, __VA_ARGS__) + +/* + * fd events + */ + +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, + libxl__ev_fd_callback *func, + int fd, short events) { + int rc; + + assert(fd >= 0); + + CTX_LOCK; + + rc = OSEVENT_HOOK(fd_register, fd, &ev->for_app_reg, events, ev); + if (rc) goto out; + + LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry); + + ev->fd = fd; + ev->events = events; + ev->in_beforepolled = -1; + ev->func = func; + + rc = 0; + + out: + CTX_UNLOCK; + return rc; +} + +int libxl__ev_fd_modify(libxl__gc *gc, libxl__ev_fd *ev, short events) { + int rc; + + CTX_LOCK; + assert(libxl__ev_fd_isregistered(ev)); + + rc = OSEVENT_HOOK(fd_modify, ev->fd, &ev->for_app_reg, events); + if (rc) goto out; + + ev->events = events; + + rc = 0; + out: + CTX_UNLOCK; + return rc; +} + +void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev) { + CTX_LOCK; + + if (!libxl__ev_fd_isregistered(ev)) + goto out; + + OSEVENT_HOOK_VOID(fd_deregister, ev->fd, ev->for_app_reg); + LIBXL_LIST_REMOVE(ev, entry); + ev->fd = -1; + + if (ev->in_beforepolled >= 0 && + ev->in_beforepolled < CTX->fd_beforepolled_used) + /* remove stale reference */ + CTX->fd_beforepolled[ev->in_beforepolled] = NULL; + + out: + CTX_UNLOCK; +} + +/* + * timeouts + */ + + +int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r) { + int rc = gettimeofday(now_r, 0); + if (rc) { + LIBXL__LOG_ERRNO(CTX, LIBXL__LOG_ERROR, "gettimeofday failed"); + return ERROR_FAIL; + } + return 0; +} + +static int time_rel_to_abs(libxl__gc *gc, int ms, struct timeval *abs_out) { + int rc; + struct timeval additional = { + .tv_sec = ms / 1000, + .tv_usec = (ms % 1000) * 1000 + }; + struct timeval now; + + rc = libxl__gettimeofday(gc, &now); + if (rc) return rc; + + timeradd(&now, &additional, abs_out); + return 0; +} + +static void time_insert_finite(libxl__gc *gc, libxl__ev_time *ev) { + libxl__ev_time *evsearch; + LIBXL_TAILQ_INSERT_SORTED(&CTX->etimes, entry, ev, evsearch, , + timercmp(&ev->abs, &evsearch->abs, >)); + ev->infinite = 0; +} + +static int time_register_finite(libxl__gc *gc, libxl__ev_time *ev, + struct timeval abs) { + int rc; + + rc = OSEVENT_HOOK(timeout_register, &ev->for_app_reg, abs, ev); + if (rc) return rc; + + ev->infinite = 0; + ev->abs = abs; + time_insert_finite(gc, ev); + + return 0; +} + +static void time_deregister(libxl__gc *gc, libxl__ev_time *ev) { + if (!ev->infinite) { + OSEVENT_HOOK_VOID(timeout_deregister, &ev->for_app_reg); + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); + } +} + + +int libxl__ev_time_register_abs(libxl__gc *gc, libxl__ev_time *ev, + libxl__ev_time_callback *func, + struct timeval abs) { + int rc; + + CTX_LOCK; + + rc = time_register_finite(gc, ev, abs); + if (rc) goto out; + + ev->func = func; + + rc = 0; + out: + CTX_UNLOCK; + return rc; +} + + +int libxl__ev_time_register_rel(libxl__gc *gc, libxl__ev_time *ev, + libxl__ev_time_callback *func, + int milliseconds /* as for poll(2) */) { + struct timeval abs; + int rc; + + CTX_LOCK; + + if (milliseconds < 0) { + ev->infinite = 1; + } else { + rc = time_rel_to_abs(gc, milliseconds, &abs); + if (rc) goto out; + + rc = time_register_finite(gc, ev, abs); + if (rc) goto out; + } + + ev->func = func; + rc = 0; + + out: + CTX_UNLOCK; + return 0; +} + +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev, + struct timeval abs) { + int rc; + + CTX_LOCK; + + assert(libxl__ev_time_isregistered(ev)); + + if (ev->infinite) { + rc = time_register_finite(gc, ev, abs); + if (rc) goto out; + } else { + rc = OSEVENT_HOOK(timeout_modify, &ev->for_app_reg, abs); + if (rc) goto out; + + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); + ev->abs = abs; + time_insert_finite(gc, ev); + } + + rc = 0; + out: + CTX_UNLOCK; + return rc; +} + +int libxl__ev_time_modify_rel(libxl__gc *gc, libxl__ev_time *ev, + int milliseconds) { + struct timeval abs; + int rc; + + CTX_LOCK; + + assert(libxl__ev_time_isregistered(ev)); + + if (milliseconds < 0) { + time_deregister(gc, ev); + ev->infinite = 1; + rc = 0; + goto out; + } + + rc = time_rel_to_abs(gc, milliseconds, &abs); + if (rc) goto out; + + rc = libxl__ev_time_modify_abs(gc, ev, abs); + if (rc) goto out; + + rc = 0; + out: + CTX_UNLOCK; + return 0; +} + +void libxl__ev_time_deregister(libxl__gc *gc, libxl__ev_time *ev) { + CTX_LOCK; + + if (!libxl__ev_time_isregistered(ev)) + goto out; + + time_deregister(gc, ev); + ev->func = 0; + + out: + CTX_UNLOCK; + return; +} + + +/* + * xenstore watches + */ + +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum) { + libxl__ev_watch_slot *slot = &CTX->watch_slots[slotnum]; + libxl__ev_watch_slot *slotcontents = LIBXL_SLIST_NEXT(slot, empty); + + if (slotcontents == NULL || + ((uintptr_t)slotcontents >= (uintptr_t)CTX->watch_slots && + (uintptr_t)slotcontents < (uintptr_t)(CTX->watch_slots + + CTX->watch_nslots))) + /* An empty slot has either a NULL pointer (end of the + * free list), or a pointer to another entry in the array. + * So we can do a bounds check to distinguish empty from + * full slots. + */ + /* We need to do the comparisons as uintptr_t because + * comparing pointers which are not in the same object is + * undefined behaviour; if the compiler managed to figure + * out that watch_slots[0..watch_nslots-1] is all of the + * whole array object it could prove that the above bounds + * check was always true if it was legal, and remove it! + * + * uintptr_t because even on a machine with signed + * pointers, objects do not cross zero; whereas on + * machines with unsigned pointers, they may cross + * 0x8bazillion. + */ + return NULL; + + /* see comment near libxl__ev_watch_slot definition */ + return (void*)slotcontents; +} + +static void watchfd_callback(libxl__gc *gc, libxl__ev_fd *ev, + int fd, short events, short revents) { + for (;;) { + char **event = xs_check_watch(CTX->xsh); + if (!event) { + if (errno == EAGAIN) break; + if (errno == EINTR) continue; + LIBXL__EVENT_DISASTER(gc, "cannot check/read watches", errno, 0); + return; + } + + const char *epath = event[0]; + const char *token = event[1]; + int slotnum; + uint32_t counterval; + int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval); + if (rc != 2) { + LIBXL__LOG(CTX, LIBXL__LOG_ERROR, + "watch epath=%s token=%s: failed to parse token", + epath, token); + /* oh well */ + goto ignore; + } + if (slotnum < 0 || slotnum >= CTX->watch_nslots) { + /* perhaps in the future we will make the watchslots array shrink */ + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, "watch epath=%s token=%s:" + " slotnum %d out of range [0,%d>", + epath, token, slotnum, CTX->watch_nslots); + goto ignore; + } + + libxl__ev_xswatch *w = libxl__watch_slot_contents(gc, slotnum); + + if (!w) { + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, + "watch epath=%s token=%s: empty slot", + epath, token); + goto ignore; + } + + if (w->counterval != counterval) { + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, + "watch epath=%s token=%s: counter != %"PRIx32, + epath, token, w->counterval); + goto ignore; + } + + /* Now it''s possible, though unlikely, that this was an event + * from a previous use of the same slot with the same counterval. + * + * In that case either: + * - the event path is a child of the watch path, in + * which case this watch would really have generated this + * event if it had been registered soon enough and we are + * OK to give this possibly-spurious event to the caller; or + * - it is not, in which case we must suppress it as the + * caller should not see events for unrelated paths. + * + * See also docs/misc/xenstore.txt. + */ + size_t epathlen = strlen(epath); + size_t wpathlen = strlen(w->path); + if (epathlen < wpathlen || + memcmp(epath, w->path, wpathlen) || + (epathlen > wpathlen && epath[wpathlen] != ''/'')) { + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, + "watch epath=%s token=%s: not child of wpath=%s", + epath, token, w->path); + goto ignore; + } + + /* At last, we have checked everything! */ + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, + "watch event: epath=%s token=%s wpath=%s w=%p", + epath, token, w->path, w); + w->callback(gc, w, w->path, epath); + + ignore: + free(event); + } +} + +static char *watch_token(libxl__gc *gc, int slotnum, uint32_t counterval) { + return libxl__sprintf(gc, "%d/%"PRIx32, slotnum, counterval); +} + +int libxl__ev_xswatch_register(libxl__gc *gc, libxl__ev_xswatch *w, + libxl__ev_xswatch_callback *func, + const char *path /* copied */) { + libxl__ev_watch_slot *use = NULL; + char *path_copy = NULL; + int rc; + + CTX_LOCK; + + if (!libxl__ev_fd_isregistered(&CTX->watch_efd)) { + rc = libxl__ev_fd_register(gc, &CTX->watch_efd, watchfd_callback, + xs_fileno(CTX->xsh), POLLIN); + if (rc) goto out_rc; + } + + if (LIBXL_SLIST_EMPTY(&CTX->watch_freeslots)) { + /* Free list is empty so there is not in fact a linked + * free list in the array and we can safely realloc it */ + int newarraysize = (CTX->watch_nslots + 1) << 2; + int i; + libxl__ev_watch_slot *newarray + realloc(CTX->watch_slots, sizeof(*newarray) * newarraysize); + if (!newarray) goto out_nomem; + for (i=CTX->watch_nslots; i<newarraysize; i++) + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, + &newarray[i], empty); + CTX->watch_slots = newarray; + CTX->watch_nslots = newarraysize; + } + use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots); + assert(use); + LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty); + + path_copy = strdup(path); + if (!path_copy) goto out_nomem; + + int slotnum = use - CTX->watch_slots; + w->counterval = CTX->watch_counter++; + + if (!xs_watch(CTX->xsh, path, watch_token(gc, slotnum, w->counterval))) { + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, + "create watch for path %s", path); + rc = ERROR_FAIL; + goto out_rc; + } + + w->slotnum = slotnum; + w->path = path_copy; + w->callback = func; + /* we look a bit behind the curtain of LIBXL_SLIST, to explictly + * assign to the pointer that''s the next link. See the comment + * by the definitionn of libxl__ev_watch_slot */ + use->empty.sle_next = (void*)w; + + CTX_UNLOCK; + return 0; + + out_nomem: + rc = ERROR_NOMEM; + out_rc: + if (use) + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, use, empty); + if (path_copy) + free(path_copy); + CTX_UNLOCK; + return rc; +} + +void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch *w) { + /* it is legal to deregister from within _callback */ + CTX_LOCK; + + if (w->slotnum >= 0) { + char *token = watch_token(gc, w->slotnum, w->counterval); + if (!xs_unwatch(CTX->xsh, w->path, token)) + /* Oh well, we will just get watch events forever more + * and ignore them. But we should complain to the log. */ + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, + "remove watch for path %s", w->path); + + libxl__ev_watch_slot *slot = &CTX->watch_slots[w->slotnum]; + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, slot, empty); + } + + free(w->path); + w->path = NULL; + + CTX_UNLOCK; +} + +/* + * osevent poll + */ + +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, + struct pollfd *fds, int *timeout_upd, + struct timeval now) { + libxl__ev_fd *efd; + int i; + + /* + * In order to be able to efficiently find the libxl__ev_fd + * for a struct poll during _afterpoll, we maintain a shadow + * data structure in CTX->fd_beforepolled: each slot in + * the fds array corresponds to a slot in fd_beforepolled. + */ + + GC_INIT(ctx); + CTX_LOCK; + + if (*nfds_io) { + /* + * As an optimisation, we don''t touch fd_beforepolled_used + * if *nfds_io is zero on entry, since in that case the + * caller just wanted to know how big an array to give us. + * + * If !*nfds_io, the unconditional parts below are guaranteed + * not to mess with fd_beforepolled... or any in_beforepolled. + */ + + /* Remove all the old references into beforepolled */ + for (i = 0; i < CTX->fd_beforepolled_used; i++) { + efd = CTX->fd_beforepolled[i]; + if (efd) { + assert(efd->in_beforepolled == i); + efd->in_beforepolled = -1; + CTX->fd_beforepolled[i] = NULL; + } + } + CTX->fd_beforepolled_used = 0; + + /* make sure our array is as big as *nfds_io */ + if (CTX->fd_beforepolled_allocd < *nfds_io) { + assert(*nfds_io < INT_MAX / sizeof(libxl__ev_fd*) / 2); + libxl__ev_fd **newarray + realloc(CTX->fd_beforepolled, sizeof(*newarray) * *nfds_io); + if (!newarray) + return ERROR_NOMEM; + CTX->fd_beforepolled = newarray; + CTX->fd_beforepolled_allocd = *nfds_io; + } + } + + int used = 0; + LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) { + if (used < *nfds_io) { + fds[used].fd = efd->fd; + fds[used].events = efd->events; + fds[used].revents = 0; + CTX->fd_beforepolled[used] = efd; + efd->in_beforepolled = used; + } + used++; + } + int rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL; + + if (*nfds_io) { + CTX->fd_beforepolled_used = used; + } + + *nfds_io = used; + + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); + if (etime) { + int our_timeout; + struct timeval rel; + static struct timeval zero; + + timersub(&etime->abs, &now, &rel); + + if (timercmp(&rel, &zero, <)) { + our_timeout = 0; + } else if (rel.tv_sec >= 2000000) { + our_timeout = 2000000000; + } else { + our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000; + } + if (*timeout_upd < 0 || our_timeout < *timeout_upd) + *timeout_upd = our_timeout; + } + + CTX_UNLOCK; + GC_FREE; + return rc; +} + +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, + struct timeval now) { + int i; + GC_INIT(ctx); + CTX_LOCK; + + assert(nfds <= CTX->fd_beforepolled_used); + + for (i = 0; i < nfds; i++) { + if (!fds[i].revents) + continue; + + libxl__ev_fd *efd = CTX->fd_beforepolled[i]; + if (!efd) + continue; + + assert(efd->in_beforepolled == i); + assert(fds[i].fd == efd->fd); + + int revents = fds[i].revents & efd->events; + if (!revents) + continue; + + efd->func(gc, efd, efd->fd, efd->events, revents); + } + + for (;;) { + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); + if (!etime) + break; + + assert(!etime->infinite); + + if (timercmp(&etime->abs, &now, >)) + break; + + time_deregister(gc, etime); + + etime->func(gc, etime, &etime->abs); + } + + CTX_UNLOCK; + GC_FREE; +} + + +/* + * osevent hook and callback machinery + */ + +void libxl_osevent_register_hooks(libxl_ctx *ctx, + const libxl_osevent_hooks *hooks, + void *user) { + GC_INIT(ctx); + CTX_LOCK; + ctx->osevent_hooks = hooks; + ctx->osevent_user = user; + CTX_UNLOCK; + GC_FREE; +} + + +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl, + int fd, short events, short revents) { + libxl__ev_fd *ev = for_libxl; + + GC_INIT(ctx); + CTX_LOCK; + assert(!CTX->osevent_in_hook); + + assert(fd == ev->fd); + revents &= ev->events; + if (revents) + ev->func(gc, ev, fd, ev->events, revents); + + CTX_UNLOCK; + GC_FREE; +} + +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl) { + libxl__ev_time *ev = for_libxl; + + GC_INIT(ctx); + CTX_LOCK; + assert(!CTX->osevent_in_hook); + + assert(!ev->infinite); + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); + ev->func(gc, ev, &ev->abs); + + CTX_UNLOCK; + GC_FREE; +} + +void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval, + libxl_event_type type /* may be 0 */, + const char *file, int line, const char *func) { + libxl__log(CTX, XTL_CRITICAL, errnoval, file, line, func, + "DISASTER in event loop: %s%s%s%s", + msg, + type ? " (relates to event type " : "", + type ? libxl_event_type_to_string(type) : "", + type ? ")" : ""); + + /* + * FIXME: This should call the "disaster" hook supplied to + * libxl_event_register_callbacks, which will be introduced in the + * next patch. + */ + + const char verybad[] + "DISASTER in event loop not handled by libxl application"; + LIBXL__LOG(CTX, XTL_CRITICAL, verybad); + fprintf(stderr, "libxl: fatal error, exiting program: %s\n", verybad); + exit(-1); +} + +/* + * Local variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h new file mode 100644 index 0000000..25efbdf --- /dev/null +++ b/tools/libxl/libxl_event.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2011 Citrix Ltd. + * Author Ian Jackson <ian.jackson@eu.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. + */ + +#ifndef LIBXL_EVENT_H +#define LIBXL_EVENT_H + +#include <libxl.h> + + +/*======================================================================*/ + +/* + * OS event handling - passing low-level OS events to libxl + * + * Event-driven programs must use these facilities to allow libxl + * to become aware of readability/writeability of file descriptors + * and the occurrence of timeouts. + * + * There are two approaches available. The first is appropriate for + * simple programs handling reasonably small numbers of domains: + * + * for (;;) { + * libxl_osevent_beforepoll(...) + * poll(); + * libxl_osevent_afterpoll(...); + * for (;;) { + * r=libxl_event_check(...); + * if (r==LIBXL_NOT_READY) break; + * if (r) handle failure; + * do something with the event; + * } + * } + * + * The second approach uses libxl_osevent_register_hooks and is + * suitable for programs which are already using a callback-based + * event library. + * + * An application may freely mix the two styles of interaction. + */ + +struct pollfd; + +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, + struct pollfd *fds, int *timeout_upd, + struct timeval now); + /* The caller should provide beforepoll with some space for libxl''s + * fds, and tell libxl how much space is available by setting *nfds_io. + * fds points to the start of this space (and fds may be a pointer into + * a larger array, for example, if the application has some fds of + * its own that it is interested in). + * + * On return *nfds_io will in any case have been updated by libxl + * according to how many fds libxl wants to poll on. + * + * If the space was sufficient, libxl fills in fds[0..<new + * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed, + * and returns ok. + * + * If space was insufficient, fds[0..<old *nfds_io>] is undefined on + * return; *nfds_io on return will be greater than the value on + * entry; *timeout_upd may or may not have been updated; and + * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this case + * the application needs to make more space (enough space for + * *nfds_io struct pollfd) and then call beforepoll again, before + * entering poll(2). Typically this will involve calling realloc. + * + * The application may call beforepoll with fds==NULL and + * *nfds_io==0 in order to find out how much space is needed. + * + * *timeout_upd is as for poll(2): it''s in milliseconds, and + * negative values mean no timeout (infinity). + * libxl_osevent_beforepoll will only reduce the timeout, naturally. + */ +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, + struct timeval now); + /* nfds and fds[0..nfds] must be from the most recent call to + * _beforepoll, as modified by poll. + * + * This function actually performs all of the IO and other actions, + * and generates events (libxl_event), which are implied by either + * (a) the time of day or (b) both (i) the returned information from + * _beforepoll, and (ii) the results from poll specified in + * fds[0..nfds-1]. Generated events can then be retrieved by + * libxl_event_check. + */ + + +typedef struct libxl_osevent_hooks { + int (*fd_register)(void *user, int fd, void **for_app_registration_out, + short events, void *for_libxl); + int (*fd_modify)(void *user, int fd, void **for_app_registration_update, + short events); + void (*fd_deregister)(void *user, int fd, void *for_app_registration); + int (*timeout_register)(void *user, void **for_app_registration_out, + struct timeval abs, void *for_libxl); + int (*timeout_modify)(void *user, void **for_app_registration_update, + struct timeval abs); + void (*timeout_deregister)(void *user, void *for_app_registration_io); +} libxl_osevent_hooks; + +void libxl_osevent_register_hooks(libxl_ctx *ctx, + const libxl_osevent_hooks *hooks, + void *user); + /* The application which calls register_fd_hooks promises to + * maintain a register of fds and timeouts that libxl is interested + * in, and make calls into libxl (libxl_osevent_occurred_*) + * when those fd events and timeouts occur. This is more efficient + * than _beforepoll/_afterpoll if there are many fds (which can + * happen if the same libxl application is managing many domains). + * + * For an fd event, events is as for poll(). register or modify may + * be called with events==0, in which case it must still work + * normally, just not generate any events. + * + * For a timeout event, milliseconds is as for poll(). + * Specifically, negative values of milliseconds mean NO TIMEOUT. + * This is used by libxl to temporarily disable a timeout. + * + * If the register or modify hook succeeds it may update + * *for_app_registration_out/_update and must then return 0. + * On entry to register, *for_app_registration_out is always NULL. + * + * A registration or modification hook may fail, in which case it + * must leave the registration state of the fd or timeout unchanged. + * It may then either return ERROR_OSEVENT_REG_FAIL or any positive + * int. The value returned will be passed up through libxl and + * eventually returned back to the application. When register + * fails, any value stored into *for_registration_out is ignored by + * libxl; when modify fails, any changed value stored into + * *for_registration_update is honoured by libxl and will be passed + * to future modify or deregister calls. + * + * libxl will only attempt to register one callback for any one fd. + * libxl will remember the value stored in *for_app_registration_io + * by a successful call to register or modify and pass it into + * subsequent calls to modify or deregister. + * + * register_fd_hooks may be called only once for each libxl_ctx. + * libxl may make calls to register/modify/deregister from within + * any libxl function (indeed, it will usually call register from + * register_event_hooks). Conversely, the application MUST NOT make + * the event occurrence calls (libxl_osevent_occurred_*) into libxl + * reentrantly from within libxl (for example, from within the + * register/modify functions). + * + * Lock hierarchy: the register/modify/deregister functions may be + * called with locks held. These locks (the "libxl internal locks") + * are inside the libxl_ctx. Therefore, if those register functions + * acquire any locks of their own ("caller register locks") outside + * libxl, to avoid deadlock one of the following must hold for each + * such caller register lock: + * (a) "acquire libxl internal locks before caller register lock": + * No libxl function may be called with the caller register + * lock held. + * (b) "acquire caller register lock before libxl internal locks": + * No libxl function may be called _without_ the caller + * register lock held. + * Of these we would normally recommend (a). + * + * The value *hooks is not copied and must outlast the libxl_ctx. + */ + +/* It is NOT legal to call _occurred_ reentrantly within any libxl + * function. Specifically it is NOT legal to call it from within + * a register callback. Conversely, libxl MAY call register/deregister + * from within libxl_event_registered_call_*. + */ + +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl, + int fd, short events, short revents); + +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl); + /* Implicitly, on entry to this function the timeout has been + * deregistered. If _occurred_timeout is called, libxl will not + * call timeout_deregister; if it wants to requeue the timeout it + * will call timeout_register again. + */ + +#endif + +/* + * Local variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index d015c7c..88e7dbb 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -24,6 +24,9 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> +#include <inttypes.h> +#include <assert.h> +#include <sys/poll.h> #include <xs.h> #include <xenctrl.h> @@ -91,6 +94,66 @@ _hidden void libxl__log(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, /* these functions preserve errno (saving and restoring) */ +typedef struct libxl__gc libxl__gc; + +typedef struct libxl__ev_fd libxl__ev_fd; +typedef void libxl__ev_fd_callback(libxl__gc *gc, libxl__ev_fd *ev, + int fd, short events, short revents); +struct libxl__ev_fd { + /* all private for libxl__ev_fd... */ + LIBXL_LIST_ENTRY(libxl__ev_fd) entry; + int fd; + short events; + int in_beforepolled; /* -1 means not in fd_beforepolled */ + void *for_app_reg; + libxl__ev_fd_callback *func; +}; + + +typedef struct libxl__ev_time libxl__ev_time; +typedef void libxl__ev_time_callback(libxl__gc *gc, libxl__ev_time *ev, + const struct timeval *requested_abs); +struct libxl__ev_time { + /* all private for libxl__ev_time... */ + int infinite; /* not registered in list or with app if infinite */ + LIBXL_TAILQ_ENTRY(libxl__ev_time) entry; + struct timeval abs; + void *for_app_reg; + libxl__ev_time_callback *func; +}; + +typedef struct libxl__ev_xswatch libxl__ev_xswatch; +typedef void libxl__ev_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch*, + const char *watch_path, const char *event_path); +struct libxl__ev_xswatch { + /* caller should include this in their own struct */ + /* contents are private to xswatch_register */ + int slotnum; + uint32_t counterval; + char *path; + libxl__ev_xswatch_callback *callback; +}; + +/* + * An entry in the watch_slots table is either: + * 1. an entry in the free list, ie NULL or pointer to next free list entry + * 2. an pointer to a libxl__ev_xswatch + * + * But we don''t want to use unions or type-punning because the + * compiler might "prove" that our code is wrong and misoptimise it. + * + * The rules say that all struct pointers have identical + * representation and alignment requirements (C99+TC1+TC2 6.2.5p26) so + * what we do is simply declare our array as containing only the free + * list pointers, and explicitly convert from and to our actual + * xswatch pointers when we store and retrieve them. + */ +typedef struct libxl__ev_watch_slot { + LIBXL_SLIST_ENTRY(struct libxl__ev_watch_slot) empty; +} libxl__ev_watch_slot; + +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum); + struct libxl__ctx { xentoollog_logger *lg; xc_interface *xch; @@ -108,6 +171,23 @@ struct libxl__ctx { * documented in the libxl public interface. */ + int osevent_in_hook; + const libxl_osevent_hooks *osevent_hooks; + void *osevent_user; + /* See the comment for OSEVENT_HOOK_INTERN in libxl_event.c + * for restrictions on the use of the osevent fields. */ + + int fd_beforepolled_allocd, fd_beforepolled_used; + libxl__ev_fd **fd_beforepolled; /* see libxl_osevent_beforepoll */ + LIBXL_LIST_HEAD(, libxl__ev_fd) efds; + LIBXL_TAILQ_HEAD(, libxl__ev_time) etimes; + + libxl__ev_watch_slot *watch_slots; + int watch_nslots; + LIBXL_SLIST_HEAD(, libxl__ev_watch_slot) watch_freeslots; + uint32_t watch_counter; /* helps disambiguate slot reuse */ + libxl__ev_fd watch_efd; + /* for callers who reap children willy-nilly; caller must only * set this after libxl_init and before any other call - or * may leave them untouched */ @@ -138,12 +218,12 @@ typedef struct { #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y))) -typedef struct { +struct libxl__gc { /* mini-GC */ int alloc_maxsize; void **alloc_ptrs; libxl_ctx *owner; -} libxl__gc; +}; #define LIBXL_INIT_GC(gc,ctx) do{ \ (gc).alloc_maxsize = 0; \ @@ -209,9 +289,137 @@ _hidden char *libxl__xs_read(libxl__gc *gc, xs_transaction_t t, _hidden char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t, const char *path, unsigned int *nb); /* On error: returns NULL, sets errno (no logging) */ - _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid); + +/* + * Event generation functions provided by the libxl event core to the + * rest of libxl. Implemented in terms of _beforepoll/_afterpoll + * and/or the fd registration machinery, as provided by the + * application. + * + * Semantics are similar to those of the fd and timeout registration + * functions provided to libxl_osevent_register_hooks. + * + * Non-0 returns from libxl__ev_{modify,deregister} have already been + * logged by the core and should be returned unmodified to libxl''s + * caller; NB that they may be valid libxl error codes but they may + * also be positive numbers supplied by the caller. + * + * In each case, there is a libxl__ev_FOO structure which can be in + * one of three states: + * + * Undefined - Might contain anything. All-bits-zero is + * an undefined state. + * + * Idle - Struct contents are defined enough to pass to any + * libxl__ev_FOO function but not registered and + * callback will not be called. The struct does not + * contain references to any allocated resources so + * can be thrown away. + * + * Active - Request for events has been registered and events + * may be generated. _deregister must be called to + * reclaim resources. + * + * These functions are provided for each kind of event KIND: + * + * int libxl__ev_KIND_register(libxl__gc *gc, libxl__ev_KIND *GEN, + * libxl__ev_KIND_callback *FUNC, + * DETAILS); + * On entry *GEN must be in state Undefined or Idle. + * Returns a libxl error code; on error return *GEN is Idle. + * On successful return *GEN is Active and FUNC wil be + * called by the event machinery in future. FUNC will + * not be called from within the call to _register. + * + * void libxl__ev_KIND_deregister(libxl__gc *gc, libxl__ev_KIND *GEN_upd); + * On entry *GEN must be in state Active or Idle. + * On return it is Idle. (Idempotent.) + * + * void libxl__ev_KIND_init(libxl__ev_KIND *GEN); + * Provided for initialising an Undefined KIND. + * On entry *GEN must be in state Idle or Undefined. + * On return it is Idle. (Idempotent.) + * + * int libxl__ev_KIND_isregistered(const libxl__ev_KIND *GEN); + * On entry *GEN must be Idle or Active. + * Returns nonzero if it is Active, zero otherwise. + * Cannot fail. + * + * int libxl__ev_KiND_modify(libxl__gc*, libxl__ev_KIND *GEN, + * DETAILS); + * Only provided for some kinds of generator. + * On entry *GEN must be Active and on return, whether successful + * or not, it will be Active. + * Returns a libxl error code; on error the modification + * is not effective. + * + * All of these functions are fully threadsafe and may be called by + * general code in libxl even from within event callback FUNCs. + */ + + +_hidden int libxl__ev_fd_register(libxl__gc*, libxl__ev_fd *ev_out, + libxl__ev_fd_callback*, + int fd, short events /* as for poll(2) */); +_hidden int libxl__ev_fd_modify(libxl__gc*, libxl__ev_fd *ev, + short events); +_hidden void libxl__ev_fd_deregister(libxl__gc*, libxl__ev_fd *ev); +static inline void libxl__ev_fd_init(libxl__ev_fd *efd) + { efd->fd = -1; } +static inline int libxl__ev_fd_isregistered(libxl__ev_fd *efd) + { return efd->fd >= 0; } + +_hidden int libxl__ev_time_register_rel(libxl__gc*, libxl__ev_time *ev_out, + libxl__ev_time_callback*, + int milliseconds /* as for poll(2) */); +_hidden int libxl__ev_time_register_abs(libxl__gc*, libxl__ev_time *ev_out, + libxl__ev_time_callback*, + struct timeval); +_hidden int libxl__ev_time_modify_rel(libxl__gc*, libxl__ev_time *ev, + int milliseconds /* as for poll(2) */); +_hidden int libxl__ev_time_modify_abs(libxl__gc*, libxl__ev_time *ev, + struct timeval); +_hidden void libxl__ev_time_deregister(libxl__gc*, libxl__ev_time *ev); +static inline void libxl__ev_time_init(libxl__ev_time *ev) + { ev->func = 0; } +static inline int libxl__ev_time_isregistered(libxl__ev_time *ev) + { return !!ev->func; } + + +_hidden int libxl__ev_xswatch_register(libxl__gc*, libxl__ev_xswatch *xsw_out, + libxl__ev_xswatch_callback*, + const char *path /* copied */); +_hidden void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch*); + +static inline void libxl__ev_xswatch_init(libxl__ev_xswatch *xswatch_out) + { xswatch_out->slotnum = -1; } +static inline int libxl__ev_xswatch_isregistered(const libxl__ev_xswatch *xw) + { return xw->slotnum >= 0; } + + + +_hidden void libxl__event_disaster(libxl__gc*, const char *msg, int errnoval, + libxl_event_type type /* may be 0 */, + const char *file, int line, + const char *func); + /* + * In general, call this via the macro LIBXL__EVENT_DISASTER. + * + * Event-generating functions may call this if they might have + * wanted to generate an event (either an internal one ie a + * libxl__ev_FOO_callback or an application event), but are + * prevented from doing so due to eg lack of memory. + * + * NB that this function may return and the caller isn''t supposed to + * then crash, although it may fail (and henceforth leave things in + * a state where many or all calls fail). + */ +#define LIBXL__EVENT_DISASTER(gc, msg, errnoval, type) \ + libxl__event_disaster(gc, msg, errnoval, type, __FILE__, __LINE__, __func__) + + /* from xl_dom */ _hidden libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid); _hidden int libxl__domain_shutdown_reason(libxl__gc *gc, uint32_t domid); @@ -536,6 +744,8 @@ _hidden int libxl__parse_mac(const char *s, libxl_mac mac); /* compare mac address @a and @b. 0 if the same, -ve if a<b and +ve if a>b */ _hidden int libxl__compare_macs(libxl_mac *a, libxl_mac *b); +_hidden int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r); + #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) -- 1.7.2.5
Replace the existing API for retrieving high-level events (events about domains, etc.) from libxl with a new one. This changes the definition and semantics of the `libxl_event'' structure, and replaces the calls for obtaining information about domain death and disk eject events. This is an incompatible change, sorry. The alternative was to try to provide both the previous horrid API and the new one, and would also involve never using the name `libxl_event'' for the new interface. Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> --- tools/libxl/libxl.c | 302 ++++++++++++++++++++++++++++++------------ tools/libxl/libxl.h | 55 ++------- tools/libxl/libxl_event.c | 188 ++++++++++++++++++++++++--- tools/libxl/libxl_event.h | 180 ++++++++++++++++++++++++- tools/libxl/libxl_internal.c | 6 + tools/libxl/libxl_internal.h | 81 +++++++++++- tools/libxl/libxl_types.idl | 35 ++++- tools/libxl/xl_cmdimpl.c | 270 ++++++++++++++++++++++---------------- 8 files changed, 839 insertions(+), 278 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 58f280c..ba9293b 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -60,8 +60,11 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, * only as an initialiser, not as an expression. */ memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); + LIBXL_TAILQ_INIT(&ctx->occurred); + ctx->osevent_hooks = 0; + ctx->fd_polls = 0; ctx->fd_beforepolled = 0; LIBXL_LIST_INIT(&ctx->efds); LIBXL_TAILQ_INIT(&ctx->etimes); @@ -70,6 +73,9 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, LIBXL_SLIST_INIT(&ctx->watch_freeslots); libxl__ev_fd_init(&ctx->watch_efd); + LIBXL_TAILQ_INIT(&ctx->death_list); + libxl__ev_xswatch_init(&ctx->death_watch); + if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" "failed to stat %s", XENSTORE_PID_FILE); @@ -97,6 +103,13 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, return 0; } +static void free_disable_deaths(libxl__gc *gc, + struct libxl__evgen_domain_death_list *l) { + libxl_evgen_domain_death *death; + while ((death = LIBXL_TAILQ_FIRST(l))) + libxl__evdisable_domain_death(gc, death); +} + int libxl_ctx_free(libxl_ctx *ctx) { int i; @@ -104,6 +117,9 @@ int libxl_ctx_free(libxl_ctx *ctx) if (!ctx) return 0; + free_disable_deaths(gc, &CTX->death_list); + free_disable_deaths(gc, &CTX->death_reported); + for (i = 0; i < ctx->watch_nslots; i++) assert(!libxl__watch_slot_contents(gc, i)); libxl__ev_fd_deregister(gc, &ctx->watch_efd); @@ -115,6 +131,7 @@ int libxl_ctx_free(libxl_ctx *ctx) libxl_version_info_dispose(&ctx->version_info); if (ctx->xsh) xs_daemon_close(ctx->xsh); + free(ctx->fd_polls); free(ctx->fd_beforepolled); free(ctx->watch_slots); @@ -614,117 +631,173 @@ int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req) return 0; } -int libxl_get_wait_fd(libxl_ctx *ctx, int *fd) -{ - *fd = xs_fileno(ctx->xsh); - return 0; -} +static void domain_death_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch *w, + const char *wpath, const char *epath) { + libxl_evgen_domain_death *evg; + uint32_t domid; + int rc; -int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter) -{ - waiter->path = strdup("@releaseDomain"); - if (asprintf(&(waiter->token), "%d", LIBXL_EVENT_TYPE_DOMAIN_DEATH) < 0) - return -1; - if (!xs_watch(ctx->xsh, waiter->path, waiter->token)) - return -1; - return 0; -} + CTX_LOCK; -int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter) -{ - GC_INIT(ctx); - int i, rc = -1; - uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid); + evg = LIBXL_TAILQ_FIRST(&CTX->death_list); + if (!evg) goto out; - if (!domid) - domid = guest_domid; + domid = evg->domid; - for (i = 0; i < num_disks; i++) { - if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", - libxl__xs_get_dompath(gc, domid), - libxl__device_disk_dev_number(disks[i].vdev, - NULL, NULL)) < 0) - goto out; - if (asprintf(&(waiter[i].token), "%d", LIBXL_EVENT_TYPE_DISK_EJECT) < 0) + for (;;) { + int nentries = LIBXL_TAILQ_NEXT(evg, entry) ? 200 : 1; + xc_domaininfo_t domaininfos[nentries]; + const xc_domaininfo_t *got = domaininfos, *gotend; + + rc = xc_domain_getinfolist(CTX->xch, domid, nentries, domaininfos); + if (rc == -1) { + LIBXL__EVENT_DISASTER(gc, "xc_domain_getinfolist failed while" + " processing @releaseDomain watch event", + errno, 0); goto out; - xs_watch(ctx->xsh, waiter[i].path, waiter[i].token); + } + gotend = &domaininfos[rc]; + + for (;;) { + if (!evg) + goto all_reported; + + if (!rc || got->domain > evg->domid) { + /* ie, the list doesn''t contain evg->domid any more so + * the domain has been destroyed */ + libxl_evgen_domain_death *evg_next; + + libxl_event *ev = NEW_EVENT(gc, DOMAIN_DESTROY, evg->domid); + if (!ev) goto out; + + libxl__event_occurred(gc, ev); + + evg->death_reported = 1; + evg_next = LIBXL_TAILQ_NEXT(evg, entry); + LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry); + LIBXL_TAILQ_INSERT_HEAD(&CTX->death_reported, evg, entry); + evg = evg_next; + + continue; + } + + if (got == gotend) + break; + + if (got->domain < evg->domid) { + got++; + continue; + } + + assert(evg->domid == got->domain); + + if (!evg->shutdown_reported && + (got->flags & XEN_DOMINF_shutdown)) { + libxl_event *ev = NEW_EVENT(gc, DOMAIN_SHUTDOWN, got->domain); + if (!ev) goto out; + + ev->u.domain_shutdown.shutdown_reason + (got->flags >> XEN_DOMINF_shutdownshift) & + XEN_DOMINF_shutdownmask; + libxl__event_occurred(gc, ev); + + evg->shutdown_reported = 1; + } + evg = LIBXL_TAILQ_NEXT(evg, entry); + } + + assert(rc); /* rc==0 results in us eating all evgs and quitting */ + domid = gotend[-1].domain; } - rc = 0; -out: - GC_FREE; - return rc; + all_reported: + out: + + CTX_UNLOCK; } -int libxl_get_event(libxl_ctx *ctx, libxl_event *event) -{ - unsigned int num; - char **events = xs_read_watch(ctx->xsh, &num); - if (num != 2) { - free(events); - return ERROR_FAIL; +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid, + libxl_ev_user user, libxl_evgen_domain_death **evgen_out) { + GC_INIT(ctx); + libxl_evgen_domain_death *evg, *evg_search; + int rc; + + CTX_LOCK; + + evg = malloc(sizeof(*evg)); if (!evg) { rc = ERROR_NOMEM; goto out; } + memset(evg, 0, sizeof(*evg)); + evg->domid = domid; + evg->user = user; + + LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, , + evg->domid > evg_search->domid); + + if (!libxl__ev_xswatch_isregistered(&ctx->death_watch)) { + rc = libxl__ev_xswatch_register(gc, &ctx->death_watch, + domain_death_xswatch_callback, "@releaseDomain"); + if (rc) { libxl__evdisable_domain_death(gc, evg); goto out; } } - event->path = strdup(events[XS_WATCH_PATH]); - event->token = strdup(events[XS_WATCH_TOKEN]); - event->type = atoi(event->token); - free(events); - return 0; -} -int libxl_stop_waiting(libxl_ctx *ctx, libxl_waiter *waiter) -{ - if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token)) - return ERROR_FAIL; - else - return 0; -} + rc = 0; -int libxl_free_event(libxl_event *event) -{ - free(event->path); - free(event->token); - return 0; -} + out: + CTX_UNLOCK; + return rc; +}; -int libxl_free_waiter(libxl_waiter *waiter) -{ - free(waiter->path); - free(waiter->token); - return 0; -} +void libxl__evdisable_domain_death(libxl__gc *gc, + libxl_evgen_domain_death *evg) { + CTX_LOCK; -int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_dominfo *info) -{ - if (libxl_domain_info(ctx, info, domid) < 0) - return 0; + if (!evg->death_reported) + LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry); + else + LIBXL_TAILQ_REMOVE(&CTX->death_reported, evg, entry); - if (info->running || (!info->shutdown && !info->dying)) - return ERROR_INVAL; + free(evg); + + if (!LIBXL_TAILQ_FIRST(&CTX->death_list) && + libxl__ev_xswatch_isregistered(&CTX->death_watch)) + libxl__ev_xswatch_deregister(gc, &CTX->death_watch); - return 1; + CTX_UNLOCK; } -int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk) -{ +void libxl_evdisable_domain_death(libxl_ctx *ctx, + libxl_evgen_domain_death *evg) { GC_INIT(ctx); - char *path; + libxl__evdisable_domain_death(gc, evg); + GC_FREE; +} + +static void disk_eject_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch *watch, + const char *wpath, const char *epath) { + libxl_evgen_disk_eject *evg = (void*)watch; char *backend; char *value; char backend_type[BACKEND_STRING_SIZE+1]; - value = libxl__xs_read(gc, XBT_NULL, event->path); + value = libxl__xs_read(gc, XBT_NULL, wpath); - if (!value || strcmp(value, "eject")) { - GC_FREE; - return 0; + if (!value || strcmp(value, "eject")) + return; + + if (libxl__xs_write(gc, XBT_NULL, wpath, "")) { + LIBXL__EVENT_DISASTER(gc, "xs_write failed acknowledging eject", + errno, LIBXL_EVENT_TYPE_DISK_EJECT); + return; } - path = strdup(event->path); - path[strlen(path) - 6] = ''\0''; - backend = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend", path)); + libxl_event *ev = NEW_EVENT(gc, DISK_EJECT, evg->domid); + libxl_device_disk *disk = &ev->u.disk_eject.disk; + + backend = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%.*s/backend", + (int)strlen(wpath)-6, wpath)); sscanf(backend, - "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE) "[a-z]/%*d/%*d", - &disk->backend_domid, backend_type); + "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE) + "[a-z]/%*d/%*d", + &disk->backend_domid, backend_type); if (!strcmp(backend_type, "tap") || !strcmp(backend_type, "vbd")) { disk->backend = LIBXL_DISK_BACKEND_TAP; } else if (!strcmp(backend_type, "qdisk")) { @@ -733,19 +806,72 @@ int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event disk->backend = LIBXL_DISK_BACKEND_UNKNOWN; } - disk->pdev_path = strdup(""); + disk->pdev_path = strdup(""); /* xxx fixme malloc failure */ disk->format = LIBXL_DISK_FORMAT_EMPTY; /* this value is returned to the user: do not free right away */ - disk->vdev = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "%s/dev", backend), NULL); + disk->vdev = xs_read(CTX->xsh, XBT_NULL, + libxl__sprintf(gc, "%s/dev", backend), NULL); disk->removable = 1; disk->readwrite = 0; disk->is_cdrom = 1; - free(path); + libxl__event_occurred(gc, ev); +} + +int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t guest_domid, + const char *vdev, libxl_ev_user user, + libxl_evgen_disk_eject **evgen_out) { + GC_INIT(ctx); + int rc; + char *path; + libxl_evgen_disk_eject *evg = NULL; + + evg = malloc(sizeof(*evg)); if (!evg) { rc = ERROR_NOMEM; goto out; } + memset(evg, 0, sizeof(*evg)); + evg->user = user; + evg->domid = guest_domid; + + evg->vdev = strdup(vdev); + if (!evg->vdev) { rc = ERROR_NOMEM; goto out; } + + uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid); + + if (!domid) + domid = guest_domid; + + path = libxl__sprintf(gc, "%s/device/vbd/%d/eject", + libxl__xs_get_dompath(gc, domid), + libxl__device_disk_dev_number(vdev, NULL, NULL)); + if (!path) { rc = ERROR_NOMEM; goto out; } + + rc = libxl__ev_xswatch_register(gc, &evg->watch, + disk_eject_xswatch_callback, path); + if (rc) goto out; + GC_FREE; - return 1; + return 0; + + out: + if (evg) + libxl__evdisable_disk_eject(gc, evg); + GC_FREE; + return rc; } +void libxl__evdisable_disk_eject(libxl__gc *gc, libxl_evgen_disk_eject *evg) { + if (libxl__ev_xswatch_isregistered(&evg->watch)) + libxl__ev_xswatch_deregister(gc, &evg->watch); + + free(evg->vdev); + free(evg); +} + +void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject *evg) { + GC_INIT(ctx); + libxl__evdisable_disk_eject(gc, evg); + GC_FREE; +} + int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) { GC_INIT(ctx); diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 654a5b0..17b15a6 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -53,7 +53,10 @@ * A public function may be called from within libxl; the call * context initialisation macros will make sure that the internal * caller''s context is reused (eg, so that the same xenstore - * transaction is used). + * transaction is used). But in-libxl callers of libxl public + * functions should note that any libxl public function may cause + * recursively reentry into libxl via the application''s event + * callback hook. * * Public functions have names like libxl_foobar. * @@ -152,6 +155,8 @@ void libxl_key_value_list_dispose(libxl_key_value_list *kvl); typedef uint32_t libxl_hwcap[8]; +typedef uint64_t libxl_ev_user; + typedef struct { uint32_t size; /* number of bytes in map */ uint8_t *map; @@ -200,6 +205,9 @@ typedef struct { int v; } libxl_enum_string_table; +struct libxl_event; +typedef LIBXL_TAILQ_ENTRY(struct libxl_event) libxl_ev_link; + typedef struct libxl__ctx libxl_ctx; #include "_libxl_types.h" @@ -298,51 +306,6 @@ int libxl_run_bootloader(libxl_ctx *ctx, /* 0 means ERROR_ENOMEM, which we have logged */ -/* events handling */ - -typedef struct { - /* event type */ - libxl_event_type type; - /* data for internal use of the library */ - char *path; - char *token; -} libxl_event; - -typedef struct { - char *path; - char *token; -} libxl_waiter; - - -int libxl_get_wait_fd(libxl_ctx *ctx, int *fd); -/* waiter is allocated by the caller */ -int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter); -/* waiter is a preallocated array of num_disks libxl_waiter elements */ -int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter); -int libxl_get_event(libxl_ctx *ctx, libxl_event *event); -int libxl_stop_waiting(libxl_ctx *ctx, libxl_waiter *waiter); -int libxl_free_event(libxl_event *event); -int libxl_free_waiter(libxl_waiter *waiter); - -/* - * Returns: - * - 0 if the domain is dead but there is no cleanup to be done. e.g - * because someone else has already done it. - * - 1 if the domain is dead and there is cleanup to be done. - * - * Can return error if the domain exists and is still running. - * - * *info will contain valid domain state iff 1 is returned. In - * particular if 1 is returned then info->shutdown_reason is - * guaranteed to be valid since by definition the domain is - * (shutdown||dying)) - */ -int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_dominfo *info); - -/* - * Returns true and fills *disk if the caller should eject the disk - */ -int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk); int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid, const char *old_name, const char *new_name); diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c index 8d4dbf6..ec5c25e 100644 --- a/tools/libxl/libxl_event.c +++ b/tools/libxl/libxl_event.c @@ -493,9 +493,9 @@ void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch *w) { * osevent poll */ -int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, - struct pollfd *fds, int *timeout_upd, - struct timeval now) { +static int beforepoll_unlocked(libxl__gc *gc, int *nfds_io, + struct pollfd *fds, int *timeout_upd, + struct timeval now) { libxl__ev_fd *efd; int i; @@ -506,9 +506,6 @@ int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, * the fds array corresponds to a slot in fd_beforepolled. */ - GC_INIT(ctx); - CTX_LOCK; - if (*nfds_io) { /* * As an optimisation, we don''t touch fd_beforepolled_used @@ -580,16 +577,25 @@ int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, *timeout_upd = our_timeout; } - CTX_UNLOCK; - GC_FREE; return rc; } -void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, + struct pollfd *fds, int *timeout_upd, struct timeval now) { - int i; + GC_INIT(ctx); CTX_LOCK; + int rc = beforepoll_unlocked(gc, nfds_io, fds, timeout_upd, now); + CTX_UNLOCK; + GC_FREE; + return rc; +} + +static void afterpoll_unlocked(libxl__gc *gc, + int nfds, const struct pollfd *fds, + struct timeval now) { + int i; assert(nfds <= CTX->fd_beforepolled_used); @@ -625,12 +631,17 @@ void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, etime->func(gc, etime, &etime->abs); } +} +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, + struct timeval now) { + GC_INIT(ctx); + CTX_LOCK; + afterpoll_unlocked(gc, nfds, fds, now); CTX_UNLOCK; GC_FREE; } - /* * osevent hook and callback machinery */ @@ -689,11 +700,10 @@ void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval, type ? libxl_event_type_to_string(type) : "", type ? ")" : ""); - /* - * FIXME: This should call the "disaster" hook supplied to - * libxl_event_register_callbacks, which will be introduced in the - * next patch. - */ + if (CTX->event_hooks && CTX->event_hooks->disaster) { + CTX->event_hooks->disaster(CTX->event_hooks_user, type, msg, errnoval); + return; + } const char verybad[] "DISASTER in event loop not handled by libxl application"; @@ -703,6 +713,152 @@ void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval, } /* + * Event retrieval etc. + */ + +void libxl_event_register_callbacks(libxl_ctx *ctx, + const libxl_event_hooks *hooks, void *user) { + ctx->event_hooks = hooks; + ctx->event_hooks_user = user; +} + +void libxl__event_occurred(libxl__gc *gc, libxl_event *event) { + if (CTX->event_hooks && + (CTX->event_hooks->event_occurs_mask & (1UL << event->type))) { + /* libxl__free_all will call the callback, just before exit + * from libxl. This helps avoid reentrancy bugs: parts of + * libxl that call libxl__event_occurred do not have to worry + * that libxl might be reentered at that point. */ + LIBXL_TAILQ_INSERT_TAIL(&gc->occurred_for_callback, event, link); + return; + } else { + LIBXL_TAILQ_INSERT_TAIL(&CTX->occurred, event, link); + } +} + +void libxl_event_free(libxl_ctx *ctx, libxl_event *event) { + libxl_event_dispose(event); + free(event); +} + +libxl_event *libxl__event_new(libxl__gc *gc, + libxl_event_type type, uint32_t domid) { + libxl_event *ev; + + ev = malloc(sizeof(*ev)); + if (!ev) { + LIBXL__EVENT_DISASTER(gc, "allocate new event", errno, type); + return NULL; + } + + memset(ev, 0, sizeof(*ev)); + ev->type = type; + ev->domid = domid; + + return ev; +} + +static int event_check_unlocked(libxl__gc *gc, libxl_event **event_r, + unsigned long typemask, + libxl_event_predicate *pred, void *pred_user) { + libxl_event *ev; + int rc; + + LIBXL_TAILQ_FOREACH(ev, &CTX->occurred, link) { + if (!(typemask & (1UL << ev->type))) + continue; + + if (pred && !pred(ev, pred_user)) + continue; + + /* got one! */ + LIBXL_TAILQ_REMOVE(&CTX->occurred, ev, link); + *event_r = ev; + rc = 0; + goto out; + } + rc = ERROR_NOT_READY; + + out: + return rc; +} + +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, + unsigned long typemask, + libxl_event_predicate *pred, void *pred_user) { + GC_INIT(ctx); + CTX_LOCK; + int rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); + CTX_UNLOCK; + GC_FREE; + return rc; +} + +int libxl_event_wait(libxl_ctx *ctx, libxl_event **event_r, + unsigned long typemask, + libxl_event_predicate *pred, void *pred_user) { + int rc; + struct timeval now; + + GC_INIT(ctx); + CTX_LOCK; + + for (;;) { + rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); + if (rc != ERROR_NOT_READY) goto out; + + rc = libxl__gettimeofday(gc, &now); + if (rc) goto out; + + int timeout; + + for (;;) { + int nfds = CTX->fd_polls_allocd; + timeout = -1; + rc = beforepoll_unlocked(gc, &nfds, CTX->fd_polls, &timeout, now); + if (!rc) break; + if (rc != ERROR_BUFFERFULL) goto out; + + struct pollfd *newarray + (nfds > INT_MAX / sizeof(struct pollfd) / 2) ? 0 : + realloc(CTX->fd_polls, sizeof(*newarray) * nfds); + + if (!newarray) { rc = ERROR_NOMEM; goto out; } + + CTX->fd_polls = newarray; + CTX->fd_polls_allocd = nfds; + } + + rc = poll(CTX->fd_polls, CTX->fd_polls_allocd, timeout); + if (rc < 0) { + if (errno == EINTR) continue; + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, "poll failed"); + rc = ERROR_FAIL; + goto out; + } + + rc = libxl__gettimeofday(gc, &now); + if (rc) goto out; + + afterpoll_unlocked(gc, CTX->fd_polls_allocd, CTX->fd_polls, now); + + /* we unlock and free the gc each time we go through this loop, + * so that (a) we don''t accumulate garbage and (b) any events + * which are to be dispatched by callback are actually delivered + * in a timely fashion. + */ + CTX_UNLOCK; + libxl__free_all(gc); + CTX_LOCK; + } + + out: + CTX_UNLOCK; + GC_FREE; + return rc; +} + +/* * Local variables: * mode: C * c-basic-offset: 4 diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h index 25efbdf..bbe1ed0 100644 --- a/tools/libxl/libxl_event.h +++ b/tools/libxl/libxl_event.h @@ -18,6 +18,178 @@ #include <libxl.h> +/*======================================================================*/ + +/* + * Domain event handling - getting Xen events from libxl + */ + +#define LIBXL_EVENTMASK_ALL (~(unsigned long)0) + +typedef int libxl_event_predicate(const libxl_event*, void *user); + /* Return value is 0 if the event is unwanted or non-0 if it is. + * Predicates are not allowed to fail. + */ + +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, + unsigned long typemask, + libxl_event_predicate *predicate, void *predicate_user); + /* Searches for an event, already-happened, which matches typemask + * and predicate. predicate==0 matches any event. + * libxl_event_check returns the event, which must then later be + * freed by the caller using libxl_event_free. + * + * Returns ERROR_NOT_READY if no such event has happened. + */ + +int libxl_event_wait(libxl_ctx *ctx, libxl_event **event_r, + unsigned long typemask, + libxl_event_predicate *predicate, void *predicate_user); + /* Like libxl_event_check but blocks if no suitable events are + * available, until some are. Uses libxl_osevent_beforepoll/ + * _afterpoll so may be inefficient if very many domains are being + * handled by a single program. + */ + +void libxl_event_free(libxl_ctx *ctx, libxl_event *event); + + +/* Alternatively or additionally, the application may also use this: */ + +typedef struct libxl_event_hooks { + uint64_t event_occurs_mask; + void (*event_occurs)(void *user, const libxl_event *event); + void (*disaster)(void *user, libxl_event_type type, + const char *msg, int errnoval); +} libxl_event_hooks; + +void libxl_event_register_callbacks(libxl_ctx *ctx, + const libxl_event_hooks *hooks, void *user); + /* + * Arranges that libxl will henceforth call event_occurs for any + * events whose type is set in event_occurs_mask, rather than + * queueing the event for retrieval by libxl_event_check/wait. + * Events whose bit is clear in mask are not affected. + * + * event becomes owned by the application and must be freed, either + * by event_occurs or later. + * + * event_occurs may be NULL if mask is 0. + * + * libxl_event_register_callback also provides a way for libxl to + * report to the application that there was a problem reporting + * events; this can occur due to lack of host memory during event + * handling, or other wholly unrecoverable errors from system calls + * made by libxl. This will not happen for frivolous reasons - only + * if the system, or the Xen components of it, are badly broken. + * + * msg and errnoval will describe the action that libxl was trying + * to do, and type specifies the type of libxl events which may be + * missing. type may be 0 in which case events of all types may be + * missing. + * + * disaster may be NULL. If it is, or if _register_callbacks has + * not been called, errors of this kind are fatal to the entire + * application: libxl will print messages to its logs and to stderr + * and call exit(-1). + * + * If disaster returns, it may be the case that some or all future + * libxl calls will return errors; likewise it may be the case that + * no more events (of the specified type, if applicable) can be + * produced. An application which supplies a disaster function + * should normally react either by exiting, or by (when it has + * returned to its main event loop) shutting down libxl with + * libxl_ctx_free and perhaps trying to restart it with + * libxl_ctx_init. + * + * In any case before calling disaster, libxl will have logged a + * message with level XTL_CRITICAL. + * + * Reentrancy: it IS permitted to call libxl from within + * event_occurs. It is NOT permitted to call libxl from within + * disaster. + * + * libxl_event_register_callbacks may be called as many times, with + * different parameters, as the application likes; the most recent + * call determines the libxl behaviour. However it is NOT safe to + * call _register_callbacks concurrently with, or reentrantly from, + * any other libxl function. + * + * Calls to _register_callbacks do not affect events which have + * already occurred. + */ + + +/* + * Events are only generated if they have been requested. + * The following functions request the generation of specific events. + * + * Each set of functions for controlling event generation has this form: + * + * typedef struct libxl__evgen_FOO libxl__evgen_FOO; + * int libxl_evenable_FOO(libxl_ctx *ctx, FURTHER PARAMETERS, + * libxl_ev_user user, libxl__evgen_FOO **evgen_out); + * void libxl_evdisable_FOO(libxl_ctx *ctx, libxl__evgen_FOO *evgen); + * + * The evenable function arranges that the events (as described in the + * doc comment for the individual function) will start to be generated + * by libxl. On success, *evgen_out is set to a non-null pointer to + * an opaque struct. + * + * The user value is returned in the generated events and may be + * used by the caller for whatever it likes. The type ev_user is + * guaranteed to be an unsigned integer type which is at least + * as big as uint64_t and is also guaranteed to be big enough to + * contain any intptr_t value. + * + * If it becomes desirable to stop generation of the relevant events, + * or to reclaim the resources in libxl associated with the evgen + * structure, the same evgen value should be passed to the evdisable + * function. However, note that events which occurred prior to the + * evdisable call may still be returned. + * + * The caller may enable identical events more than once. If they do + * so, each actual occurrence will generate several events to be + * returned by libxl_event_check, with the appropriate user value(s). + * Aside from this, each occurrence of each event is returned by + * libxl_event_check exactly once. + * + * An evgen is associated with the libxl_ctx used for its creation. + * After libxl_ctx_free, all corresponding evgen handles become + * invalid and must no longer be passed to evdisable. + * + * Events enabled with evenable prior to a fork and libxl_ctx_postfork + * are no longer generated after the fork/postfork; however the evgen + * structures are still valid and must be passed to evdisable if the + * memory they use should not be leaked. + * + * Applications should ensure that they eventually retrieve every + * event using libxl_event_check or libxl_event_wait, since events + * which occur but are not retreived by the application will be queued + * inside libxl indefinitely. libxl_event_check/_wait may be O(n) + * where n is the number of queued events which do not match the + * criteria specified in the arguments to check/wait. + */ + +typedef struct libxl__evgen_domain_death libxl_evgen_domain_death; +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid, + libxl_ev_user, libxl_evgen_domain_death **evgen_out); +void libxl_evdisable_domain_death(libxl_ctx *ctx, libxl_evgen_domain_death*); + /* Arranges for the generation of DOMAIN_SHUTDOWN and DOMAIN_DESTROY + * events. A domain which is destroyed before it shuts down + * may generate only a DESTROY event. + */ + +typedef struct libxl__evgen_disk_eject libxl_evgen_disk_eject; +int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t domid, const char *vdev, + libxl_ev_user, libxl_evgen_disk_eject **evgen_out); +void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject*); + /* Arranges for the generation of DISK_EJECT events. A copy of the + * string *vdev will be made for libxl''s internal use, and a pointer + * to this (or some other) copy will be returned as the vdev + * member of event.u. + */ + /*======================================================================*/ @@ -36,10 +208,10 @@ * poll(); * libxl_osevent_afterpoll(...); * for (;;) { - * r=libxl_event_check(...); - * if (r==LIBXL_NOT_READY) break; - * if (r) handle failure; - * do something with the event; + * r = libxl_event_check(...); + * if (r==LIBXL_NOT_READY) break; + * if (r) goto error_out; + * do something with the event; * } * } * diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index a2e5820..314ae0d 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -74,6 +74,12 @@ void libxl__free_all(libxl__gc *gc) free(gc->alloc_ptrs); gc->alloc_ptrs = 0; gc->alloc_maxsize = 0; + + libxl_event *ev, *ev_tmp; + LIBXL_TAILQ_FOREACH_SAFE(ev, &gc->occurred_for_callback, link, ev_tmp) { + LIBXL_TAILQ_REMOVE(&gc->occurred_for_callback, ev, link); + CTX->event_hooks->event_occurs(CTX->event_hooks_user, ev); + } } void *libxl__zalloc(libxl__gc *gc, int bytes) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 88e7dbb..518a06d 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -154,11 +154,44 @@ typedef struct libxl__ev_watch_slot { libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum); + +/* + * evgen structures, which are the state we use for generating + * events for the caller. + * + * In general in each case there''s an internal and an external + * version of the _evdisable_FOO function; the internal one is + * used during cleanup. + */ + +struct libxl__evgen_domain_death { + uint32_t domid; + unsigned shutdown_reported:1, death_reported:1; + LIBXL_TAILQ_ENTRY(libxl_evgen_domain_death) entry; + /* on list .death_reported ? CTX->death_list : CTX->death_reported */ + libxl_ev_user user; +}; +_hidden void +libxl__evdisable_domain_death(libxl__gc*, libxl_evgen_domain_death*); + +struct libxl__evgen_disk_eject { + libxl__ev_xswatch watch; + uint32_t domid; + libxl_ev_user user; + char *vdev; +}; +_hidden void +libxl__evdisable_disk_eject(libxl__gc*, libxl_evgen_disk_eject*); + + struct libxl__ctx { xentoollog_logger *lg; xc_interface *xch; struct xs_handle *xsh; + const libxl_event_hooks *event_hooks; + void *event_hooks_user; + pthread_mutex_t lock; /* protects data structures hanging off the ctx */ /* Always use CTX_LOCK and CTX_UNLOCK to manipulate this. * @@ -171,12 +204,17 @@ struct libxl__ctx { * documented in the libxl public interface. */ + LIBXL_TAILQ_HEAD(, libxl_event) occurred; + int osevent_in_hook; const libxl_osevent_hooks *osevent_hooks; void *osevent_user; /* See the comment for OSEVENT_HOOK_INTERN in libxl_event.c * for restrictions on the use of the osevent fields. */ + struct pollfd *fd_polls; + int fd_polls_allocd; + int fd_beforepolled_allocd, fd_beforepolled_used; libxl__ev_fd **fd_beforepolled; /* see libxl_osevent_beforepoll */ LIBXL_LIST_HEAD(, libxl__ev_fd) efds; @@ -188,6 +226,11 @@ struct libxl__ctx { uint32_t watch_counter; /* helps disambiguate slot reuse */ libxl__ev_fd watch_efd; + LIBXL_TAILQ_HEAD(libxl__evgen_domain_death_list, libxl_evgen_domain_death) + death_list /* sorted by domid */, + death_reported; + libxl__ev_xswatch death_watch; + /* for callers who reap children willy-nilly; caller must only * set this after libxl_init and before any other call - or * may leave them untouched */ @@ -223,12 +266,14 @@ struct libxl__gc { int alloc_maxsize; void **alloc_ptrs; libxl_ctx *owner; + LIBXL_TAILQ_HEAD(, libxl_event) occurred_for_callback; }; -#define LIBXL_INIT_GC(gc,ctx) do{ \ - (gc).alloc_maxsize = 0; \ - (gc).alloc_ptrs = 0; \ - (gc).owner = (ctx); \ +#define LIBXL_INIT_GC(gc,ctx) do{ \ + (gc).alloc_maxsize = 0; \ + (gc).alloc_ptrs = 0; \ + (gc).owner = (ctx); \ + LIBXL_TAILQ_INIT(&(gc).occurred_for_callback); \ } while(0) static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) @@ -250,7 +295,9 @@ static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) */ /* register @ptr in @gc for free on exit from outermost libxl callframe. */ _hidden int libxl__ptr_add(libxl__gc *gc, void *ptr); -/* if this is the outermost libxl callframe then free all pointers in @gc */ +/* if this is the outermost libxl callframe then free all pointers in @gc + * and report all occurred events via callback, if applicable. + * May reenters the application so must not be called with ctx locked. */ _hidden void libxl__free_all(libxl__gc *gc); /* allocate and zero @bytes. (similar to a gc''d malloc(3)+memzero()) */ _hidden void *libxl__zalloc(libxl__gc *gc, int bytes); @@ -400,6 +447,25 @@ static inline int libxl__ev_xswatch_isregistered(const libxl__ev_xswatch *xw) +/* + * Other event-handling support provided by the libxl event core to + * the rest of libxl. + */ + +_hidden void libxl__event_occurred(libxl__gc*, libxl_event *event); + /* Arranges to notify the application that the event has occurred. + * event should be suitable for passing to libxl_event_free. */ + +_hidden libxl_event *libxl__event_new(libxl__gc*, libxl_event_type, + uint32_t domid); + /* Convenience function. + * Allocates a new libxl_event, fills in domid and type. + * If allocation fails, calls _disaster, and returns NULL. */ + +#define NEW_EVENT(gc, type, domid) \ + libxl__event_new((gc), LIBXL_EVENT_TYPE_##type, (domid)); + /* Convenience macro. */ + _hidden void libxl__event_disaster(libxl__gc*, const char *msg, int errnoval, libxl_event_type type /* may be 0 */, const char *file, int line, @@ -412,6 +478,9 @@ _hidden void libxl__event_disaster(libxl__gc*, const char *msg, int errnoval, * libxl__ev_FOO_callback or an application event), but are * prevented from doing so due to eg lack of memory. * + * See the "disaster" member of libxl_event_hooks and associated + * comment in libxl_event.h. + * * NB that this function may return and the caller isn''t supposed to * then crash, although it may fail (and henceforth leave things in * a state where many or all calls fail). @@ -892,7 +961,7 @@ libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); */ #define GC_INIT(ctx) libxl__gc gc[1]; LIBXL_INIT_GC(gc[0],ctx) -#define GC_FREE libxl__free_all(gc) +#define GC_FREE libxl__free_all(gc) /* MUST NOT CALL WITH CTX LOCKED */ #define CTX libxl__gc_owner(gc) diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index d59d2cb..5a713f0 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -75,11 +75,6 @@ libxl_action_on_shutdown = Enumeration("action_on_shutdown", [ (6, "COREDUMP_RESTART"), ]) -libxl_event_type = Enumeration("event_type", [ - (1, "DOMAIN_DEATH"), - (2, "DISK_EJECT"), - ]) - libxl_button = Enumeration("button", [ (1, "POWER"), (2, "SLEEP"), @@ -381,3 +376,33 @@ libxl_sched_credit = Struct("sched_credit", [ ("weight", integer), ("cap", integer), ], dispose_fn=None) + +libxl_event_type = Enumeration("event_type", [ + (1, "DOMAIN_SHUTDOWN"), + (2, "DOMAIN_DESTROY"), + (3, "DISK_EJECT"), + ]) + +libxl_ev_user = Number("libxl_ev_user") + +libxl_ev_link = Builtin("ev_link", passby=PASS_BY_REFERENCE, private=True) + +libxl_event = Struct("event",[ + ("link", libxl_ev_link,0, + "for use by libxl; caller may use this once the event has been" + " returned by libxl_event_{check,wait}"), + ("domid", libxl_domid), + ("domuuid", libxl_uuid), + ("for_user", libxl_ev_user), + ("type", libxl_event_type), + ("u", KeyedUnion(None, libxl_event_type, "type", + [("domain_shutdown", Struct(None, [ + ("shutdown_reason", uint8), + ])), + ("domain_destroy", Struct(None, [])), + ("disk_eject", Struct(None, [ + ("vdev", string), + ("disk", libxl_device_disk), + ])), + ]))]) + diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index f1e729c..e5738b7 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1221,14 +1221,16 @@ skip_vfb: xlu_cfg_destroy(config); } -/* Returns 1 if domain should be restarted, 2 if domain should be renamed then restarted */ -static int handle_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_event *event, - libxl_domain_config *d_config, libxl_dominfo *info) +/* Returns 1 if domain should be restarted, + * 2 if domain should be renamed then restarted, or 0 */ +static int handle_domain_death(libxl_ctx *ctx, uint32_t domid, + libxl_event *event, + libxl_domain_config *d_config) { int restart = 0; libxl_action_on_shutdown action; - switch (info->shutdown_reason) { + switch (event->u.domain_shutdown.shutdown_reason) { case SHUTDOWN_poweroff: action = d_config->on_poweroff; break; @@ -1245,11 +1247,14 @@ static int handle_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_event *even action = d_config->on_watchdog; break; default: - LOG("Unknown shutdown reason code %d. Destroying domain.", info->shutdown_reason); + LOG("Unknown shutdown reason code %d. Destroying domain.", + event->u.domain_shutdown.shutdown_reason); action = LIBXL_ACTION_ON_SHUTDOWN_DESTROY; } - LOG("Action for shutdown reason code %d is %s", info->shutdown_reason, action_on_shutdown_names[action]); + LOG("Action for shutdown reason code %d is %s", + event->u.domain_shutdown.shutdown_reason, + action_on_shutdown_names[action]); if (action == LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY || action == LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART) { char *corefile; @@ -1314,7 +1319,7 @@ static void replace_string(char **str, const char *val) static int preserve_domain(libxl_ctx *ctx, uint32_t domid, libxl_event *event, - libxl_domain_config *d_config, libxl_dominfo *info) + libxl_domain_config *d_config) { time_t now; struct tm tm; @@ -1426,6 +1431,27 @@ static int autoconnect_console(libxl_ctx *ctx, uint32_t domid, void *priv) _exit(1); } +static int domain_wait_event(libxl_event **event_r) { + int ret; + for (;;) { + ret = libxl_event_wait(ctx, event_r, LIBXL_EVENTMASK_ALL, 0,0); + if (ret) { + LOG("Domain %d, failed to get event, quitting (rc=%d)", domid, ret); + return ret; + } + if ((*event_r)->domid != domid) { + char *evstr = libxl_event_to_json(ctx, *event_r); + LOG("INTERNAL PROBLEM - ignoring unexpected event for" + " domain %d (expected %d): event=%s", + (*event_r)->domid, domid, evstr); + free(evstr); + libxl_event_free(ctx, *event_r); + continue; + } + return ret; + } +} + static int create_domain(struct domain_create *dom_info) { libxl_domain_config d_config; @@ -1439,10 +1465,11 @@ static int create_domain(struct domain_create *dom_info) const char *restore_file = dom_info->restore_file; int migrate_fd = dom_info->migrate_fd; - int fd, i; + int i; int need_daemon = daemonize; int ret, rc; - libxl_waiter *w1 = NULL, *w2 = NULL; + libxl_evgen_domain_death *deathw = NULL; + libxl_evgen_disk_eject **diskws = NULL; /* one per disk */ void *config_data = 0; int config_len = 0; int restore_fd = -1; @@ -1647,14 +1674,14 @@ start: if (errno != EINTR) { perror("failed to wait for daemonizing child"); ret = ERROR_FAIL; - goto error_out; + goto out; } } if (status) { libxl_report_child_exitstatus(ctx, XTL_ERROR, "daemonizing child", child1, status); ret = ERROR_FAIL; - goto error_out; + goto out; } ret = domid; goto out; @@ -1691,92 +1718,106 @@ start: } LOG("Waiting for domain %s (domid %d) to die [pid %ld]", d_config.c_info.name, domid, (long)getpid()); - w1 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter) * d_config.num_disks); - w2 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter)); - libxl_wait_for_disk_ejects(ctx, domid, d_config.disks, d_config.num_disks, w1); - libxl_wait_for_domain_death(ctx, domid, w2); - libxl_get_wait_fd(ctx, &fd); - while (1) { - int ret; - fd_set rfds; - libxl_dominfo info; - libxl_event event; - libxl_device_disk disk; - FD_ZERO(&rfds); - FD_SET(fd, &rfds); + ret = libxl_evenable_domain_death(ctx, domid, 0, &deathw); + if (ret) goto out; - ret = select(fd + 1, &rfds, NULL, NULL, NULL); - if (!ret) - continue; - libxl_get_event(ctx, &event); - switch (event.type) { - case LIBXL_EVENT_TYPE_DOMAIN_DEATH: - ret = libxl_event_get_domain_death_info(ctx, domid, &event, &info); - - if (ret < 0) { - libxl_free_event(&event); - continue; + if (!diskws) { + diskws = xmalloc(sizeof(*diskws) * d_config.num_disks); + for (i = 0; i < d_config.num_disks; i++) + diskws[i] = NULL; + } + for (i = 0; i < d_config.num_disks; i++) { + ret = libxl_evenable_disk_eject(ctx, domid, d_config.disks[i].vdev, + 0, &diskws[i]); + if (ret) goto out; + } + while (1) { + libxl_event *event; + ret = domain_wait_event(&event); + if (ret) goto out; + + switch (event->type) { + + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: + LOG("Domain %d has shut down, reason code %d 0x%x", domid, + event->u.domain_shutdown.shutdown_reason, + event->u.domain_shutdown.shutdown_reason); + switch (handle_domain_death(ctx, domid, event, &d_config)) { + case 2: + if (!preserve_domain(ctx, domid, event, &d_config)) { + /* If we fail then exit leaving the old domain in place. */ + ret = -1; + goto out; } - LOG("Domain %d is dead", domid); - - if (ret) { - switch (handle_domain_death(ctx, domid, &event, &d_config, &info)) { - case 2: - if (!preserve_domain(ctx, domid, &event, &d_config, &info)) { - /* If we fail then exit leaving the old domain in place. */ - ret = -1; - goto out; - } - - /* Otherwise fall through and restart. */ - case 1: - - for (i = 0; i < d_config.num_disks; i++) - libxl_free_waiter(&w1[i]); - libxl_free_waiter(w2); - free(w1); - free(w2); - - /* - * Do not attempt to reconnect if we come round again due to a - * guest reboot -- the stdin/out will be disconnected by then. - */ - dom_info->console_autoconnect = 0; - - /* Some settings only make sense on first boot. */ - paused = 0; - if (common_domname - && strcmp(d_config.c_info.name, common_domname)) { - d_config.c_info.name = strdup(common_domname); - } - - /* - * XXX FIXME: If this sleep is not there then domain - * re-creation fails sometimes. - */ - LOG("Done. Rebooting now"); - sleep(2); - goto start; - case 0: - LOG("Done. Exiting now"); - ret = 0; - goto out; - } - } else { - LOG("Unable to get domain death info, quitting"); - goto out; + /* Otherwise fall through and restart. */ + case 1: + libxl_event_free(ctx, event); + libxl_evdisable_domain_death(ctx, deathw); + deathw = NULL; + for (i = 0; i < d_config.num_disks; i++) { + libxl_evdisable_disk_eject(ctx, diskws[i]); + diskws[i] = NULL; } - break; - case LIBXL_EVENT_TYPE_DISK_EJECT: - if (libxl_event_get_disk_eject_info(ctx, domid, &event, &disk)) { - libxl_cdrom_insert(ctx, domid, &disk); - libxl_device_disk_dispose(&disk); + /* discard any other events which may have been generated */ + while (!(ret = libxl_event_check(ctx, &event, + LIBXL_EVENTMASK_ALL, 0,0))) { + libxl_event_free(ctx, event); } - break; + if (ret != ERROR_NOT_READY) { + LOG("warning, libxl_event_check (cleanup) failed (rc=%d)", + ret); + } + + /* + * Do not attempt to reconnect if we come round again due to a + * guest reboot -- the stdin/out will be disconnected by then. + */ + dom_info->console_autoconnect = 0; + + /* Some settings only make sense on first boot. */ + paused = 0; + if (common_domname + && strcmp(d_config.c_info.name, common_domname)) { + d_config.c_info.name = strdup(common_domname); + } + + /* + * XXX FIXME: If this sleep is not there then domain + * re-creation fails sometimes. + */ + LOG("Done. Rebooting now"); + sleep(2); + goto start; + + case 0: + LOG("Done. Exiting now"); + ret = 0; + goto out; + + default: + abort(); + } + + case LIBXL_EVENT_TYPE_DOMAIN_DESTROY: + LOG("Domain %d has been destroyed.", domid); + ret = 0; + goto out; + + case LIBXL_EVENT_TYPE_DISK_EJECT: + /* XXX what is this for? */ + libxl_cdrom_insert(ctx, domid, &event->u.disk_eject.disk); + break; + + default:; + char *evstr = libxl_event_to_json(ctx, event); + LOG("warning, got unexpected event type %d, event=%s", + event->type, evstr); + free(evstr); } - libxl_free_event(&event); + + libxl_event_free(ctx, event); } error_out: @@ -2259,43 +2300,46 @@ static void destroy_domain(const char *p) static void shutdown_domain(const char *p, int wait) { int rc; + libxl_event *event; find_domain(p); rc=libxl_domain_shutdown(ctx, domid, 0); if (rc) { fprintf(stderr,"shutdown failed (rc=%d)\n",rc);exit(-1); } if (wait) { - libxl_waiter waiter; - int fd; - - libxl_wait_for_domain_death(ctx, domid, &waiter); + libxl_evgen_domain_death *deathw; - libxl_get_wait_fd(ctx, &fd); - - while (wait) { - fd_set rfds; - libxl_event event; - libxl_dominfo info; + rc = libxl_evenable_domain_death(ctx, domid, 0, &deathw); + if (rc) { + fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc); + exit(-1); + } - FD_ZERO(&rfds); - FD_SET(fd, &rfds); + for (;;) { + rc = domain_wait_event(&event); + if (rc) exit(-1); - if (!select(fd + 1, &rfds, NULL, NULL, NULL)) - continue; + switch (event->type) { - libxl_get_event(ctx, &event); + case LIBXL_EVENT_TYPE_DOMAIN_DESTROY: + LOG("Domain %d has been destroyed", domid); + goto done; - if (event.type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) { - if (libxl_event_get_domain_death_info(ctx, domid, &event, &info) < 0) - continue; + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: + LOG("Domain %d has been shut down, reason code %d %x", domid, + event->u.domain_shutdown.shutdown_reason, + event->u.domain_shutdown.shutdown_reason); + goto done; - LOG("Domain %d is dead", domid); - wait = 0; + default: + LOG("Unexpected event type %d", event->type); + break; } - - libxl_free_event(&event); + libxl_event_free(ctx, event); } - libxl_free_waiter(&waiter); + done: + libxl_event_free(ctx, event); + libxl_evdisable_domain_death(ctx, deathw); } } -- 1.7.2.5
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> Event-driven programs want to wait until the xs_fileno triggers for > reading, and then repeatedly call xs_check_watch. > > Also xs_read_watch exposes a useless "num" out parameter, which should > always (if things aren''t going hideously wrong) be at least 2 and > which the caller shouldn''t be interested in. So xs_check_watch > doesn''t have one of those. > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>Are we supposed to do something to the SONAME with this kind of change? If not then: Acked-by: Ian Campbell <ian.campbell@citrix.com> ---> tools/xenstore/xs.c | 89 ++++++++++++++++++++++++++++++++++++++++++++------- > tools/xenstore/xs.h | 16 +++++++++ > 2 files changed, 93 insertions(+), 12 deletions(-) > > diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c > index df270f7..8e54fe0 100644 > --- a/tools/xenstore/xs.c > +++ b/tools/xenstore/xs.c > @@ -132,7 +132,23 @@ struct xs_handle { > > #endif > > -static int read_message(struct xs_handle *h); > +static int read_message(struct xs_handle *h, int nonblocking); > + > +static void setnonblock(int fd, int nonblock) { > + int esave = errno; > + int flags = fcntl(fd, F_GETFL); > + if (flags == -1) > + goto out; > + > + if (nonblock) > + flags |= O_NONBLOCK; > + else > + flags &= ~O_NONBLOCK; > + > + fcntl(fd, F_SETFL, flags); > +out: > + errno = esave; > +} > > int xs_fileno(struct xs_handle *h) > { > @@ -325,8 +341,16 @@ void xs_close(struct xs_handle* xsh) > xs_daemon_close(xsh); > } > > -static bool read_all(int fd, void *data, unsigned int len) > +static bool read_all(int fd, void *data, unsigned int len, int nonblocking) > + /* With nonblocking, either reads either everything requested, > + * or nothing. */ > { > + if (!len) > + return true; > + > + if (nonblocking) > + setnonblock(fd, 1); > + > while (len) { > int done; > > @@ -334,18 +358,28 @@ static bool read_all(int fd, void *data, unsigned int len) > if (done < 0) { > if (errno == EINTR) > continue; > - return false; > + goto out_false; > } > if (done == 0) { > /* It closed fd on us? EBADF is appropriate. */ > errno = EBADF; > - return false; > + goto out_false; > } > data += done; > len -= done; > + > + if (nonblocking) { > + setnonblock(fd, 0); > + nonblocking = 0; > + } > } > > return true; > + > +out_false: > + if (nonblocking) > + setnonblock(fd, 0); > + return false; > } > > #ifdef XSTEST > @@ -374,7 +408,7 @@ static void *read_reply( > read_from_thread = read_thread_exists(h); > > /* Read from comms channel ourselves if there is no reader thread. */ > - if (!read_from_thread && (read_message(h) == -1)) > + if (!read_from_thread && (read_message(h, 0) == -1)) > return NULL; > > mutex_lock(&h->reply_mutex); > @@ -693,7 +727,8 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token) > * Returns array of two pointers: path and token, or NULL. > * Call free() after use. > */ > -char **xs_read_watch(struct xs_handle *h, unsigned int *num) > +static char **read_watch_internal(struct xs_handle *h, unsigned int *num, > + int nonblocking) > { > struct xs_stored_msg *msg; > char **ret, *strings, c = 0; > @@ -707,14 +742,20 @@ char **xs_read_watch(struct xs_handle *h, unsigned int *num) > * we haven''t called xs_watch. Presumably the application > * will do so later; in the meantime we just block. > */ > - while (list_empty(&h->watch_list) && h->fd != -1) > + while (list_empty(&h->watch_list) && h->fd != -1) { > + if (nonblocking) { > + mutex_unlock(&h->watch_mutex); > + errno = EAGAIN; > + return 0; > + } > condvar_wait(&h->watch_condvar, &h->watch_mutex); > + } > #else /* !defined(USE_PTHREAD) */ > /* Read from comms channel ourselves if there are no threads > * and therefore no reader thread. */ > > assert(!read_thread_exists(h)); /* not threadsafe but worth a check */ > - if ((read_message(h) == -1)) > + if ((read_message(h, nonblocking) == -1)) > return NULL; > > #endif /* !defined(USE_PTHREAD) */ > @@ -760,6 +801,24 @@ char **xs_read_watch(struct xs_handle *h, unsigned int *num) > return ret; > } > > +char **xs_check_watch(struct xs_handle *h) > +{ > + unsigned int num; > + char **ret; > + ret = read_watch_internal(h, &num, 1); > + if (ret) assert(num >= 2); > + return ret; > +} > + > +/* Find out what node change was on (will block if nothing pending). > + * Returns array of two pointers: path and token, or NULL. > + * Call free() after use. > + */ > +char **xs_read_watch(struct xs_handle *h, unsigned int *num) > +{ > + return read_watch_internal(h, num, 0); > +} > + > /* Remove a watch on a node. > * Returns false on failure (no watch on that node). > */ > @@ -940,11 +999,17 @@ char *xs_debug_command(struct xs_handle *h, const char *cmd, > ARRAY_SIZE(iov), NULL); > } > > -static int read_message(struct xs_handle *h) > +static int read_message(struct xs_handle *h, int nonblocking) > { > /* IMPORTANT: It is forbidden to call this function without > * acquiring the request lock and checking that h->read_thr_exists > * is false. See "Lock discipline" in struct xs_handle, above. */ > + > + /* If nonblocking==1, this function will always read either > + * nothing, returning -1 and setting errno==EAGAIN, or we read > + * whole amount requested. Ie as soon as we have the start of > + * the message we block until we get all of it. > + */ > > struct xs_stored_msg *msg = NULL; > char *body = NULL; > @@ -956,7 +1021,7 @@ static int read_message(struct xs_handle *h) > if (msg == NULL) > goto error; > cleanup_push(free, msg); > - if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr))) { /* Cancellation point */ > + if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr), nonblocking)) { /* Cancellation point */ > saved_errno = errno; > goto error_freemsg; > } > @@ -966,7 +1031,7 @@ static int read_message(struct xs_handle *h) > if (body == NULL) > goto error_freemsg; > cleanup_push(free, body); > - if (!read_all(h->fd, body, msg->hdr.len)) { /* Cancellation point */ > + if (!read_all(h->fd, body, msg->hdr.len, 0)) { /* Cancellation point */ > saved_errno = errno; > goto error_freebody; > } > @@ -1021,7 +1086,7 @@ static void *read_thread(void *arg) > struct xs_handle *h = arg; > int fd; > > - while (read_message(h) != -1) > + while (read_message(h, 0) != -1) > continue; > > /* An error return from read_message leaves the socket in an undefined > diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h > index 1cbe255..63f535d 100644 > --- a/tools/xenstore/xs.h > +++ b/tools/xenstore/xs.h > @@ -135,6 +135,22 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token); > /* Return the FD to poll on to see if a watch has fired. */ > int xs_fileno(struct xs_handle *h); > > +/* Check for node changes. On success, returns a non-NULL pointer ret > + * such that ret[0] and ret[1] are valid C strings, namely the > + * triggering path (see docs/misc/xenstore.txt) and the token (from > + * xs_watch). On error return value is NULL setting errno. > + * > + * Callers should, after xs_fileno has become readable, repeatedly > + * call xs_check_watch until it returns NULL and sets errno to EAGAIN. > + * (If the fd became readable, xs_check_watch is allowed to make it no > + * longer show up as readable even if future calls to xs_check_watch > + * will return more watch events.) > + * > + * After the caller is finished with the returned information it > + * should be freed all in one go with free(ret). > + */ > +char **xs_check_watch(struct xs_handle *h); > + > /* Find out what node change was on (will block if nothing pending). > * Returns array containing the path and token. Use XS_WATCH_* to access these > * elements. Call free() after use.
Ian Campbell
2011-Dec-07 13:55 UTC
Re: [PATCH 04/15] libxl: idl: support new "private" type attribute
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> This provides for fields in libxl datatypes which are only present in > the C version of structures and are used only by libxl itself. This > is useful when a libxl datatype wants to contain fields which are used > by libxl internally and which are only present in the structure to > avoid additional memory allocation inconvenience. > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>Acked-by: Ian Campbell <ian.campbell@citrix.com> iff you remove the stray print sys.stderr in the last hunk. Ian.> --- > tools/libxl/gentest.py | 2 ++ > tools/libxl/libxltypes.py | 4 +++- > tools/python/genwrap.py | 7 +++++++ > 3 files changed, 12 insertions(+), 1 deletions(-) > > diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py > index 05e77cc..ac7a400 100644 > --- a/tools/libxl/gentest.py > +++ b/tools/libxl/gentest.py > @@ -56,6 +56,8 @@ def gen_rand_init(ty, v, indent = " ", parent = None): > s += "%s = rand() %% 2;\n" % v > elif ty.typename in ["char *"]: > s += "%s = rand_str();\n" % v > + elif ty.private: > + pass > elif ty.typename in handcoded: > raise Exception("Gen for handcoded %s" % ty.typename) > else: > diff --git a/tools/libxl/libxltypes.py b/tools/libxl/libxltypes.py > index 55056c2..450de88 100644 > --- a/tools/libxl/libxltypes.py > +++ b/tools/libxl/libxltypes.py > @@ -33,6 +33,8 @@ class Type(object): > if self.passby not in [PASS_BY_VALUE, PASS_BY_REFERENCE]: > raise ValueError > > + self.private = kwargs.setdefault(''private'', False) > + > if typename is None: # Anonymous type > self.typename = None > self.rawname = None > @@ -50,7 +52,7 @@ class Type(object): > > self.autogenerate_dispose_fn = kwargs.setdefault(''autogenerate_dispose_fn'', True) > > - if self.typename is not None: > + if self.typename is not None and not self.private: > self.json_fn = kwargs.setdefault(''json_fn'', self.typename + "_gen_json") > else: > self.json_fn = kwargs.setdefault(''json_fn'', None) > diff --git a/tools/python/genwrap.py b/tools/python/genwrap.py > index d0c193d..ecbec11 100644 > --- a/tools/python/genwrap.py > +++ b/tools/python/genwrap.py > @@ -129,6 +129,8 @@ static PyObject *Py%(rawname)s_new(PyTypeObject *type, PyObject *args, PyObject > > l.append(''static PyGetSetDef Py%s_getset[] = {''%ty.rawname) > for f in ty.fields: > + if f.type.private: > + continue > l.append('' { .name = "%s", ''%f.name) > if ty.marshal_out(): > l.append('' .get = (getter)py_%s_%s_get, ''%(ty.rawname, f.name)) > @@ -295,9 +297,14 @@ _hidden int genwrap__ll_set(PyObject *v, long long *val, long long mask); > > """ % tuple(('' ''.join(sys.argv),) + (os.path.split(decls)[-1:]),)) > for ty in types: > + if ty.private: > + continue > if isinstance(ty, libxltypes.Aggregate): > f.write(''/* Attribute get/set functions for %s */\n''%ty.typename) > for a in ty.fields: > + print >>sys.stderr, `a`, `ty`, `a.type`, `a.type.__dict__` > + if a.type.private: > + continue > if ty.marshal_out(): > f.write(py_attrib_get(ty,a)) > if ty.marshal_in():
Ian Campbell
2011-Dec-07 14:06 UTC
Re: [PATCH 06/15] libxl: permit declaration after statement
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> GCC and C99 allow declarations to be mixed with code. This is a good > idea because: > > * It allows variables to be more often initialised as they are > declared, thus reducing the occurrence of uninitialised variable > errors. > > * Certain alloca-like constructs (arrays allocated at runtime on the > stack) can more often be written without a spurious { } block. > Such blocks are confusing to read. > > * It makes it easier to write and use macros which declare and > initialise formulaic variables and do other function setup code, > because there is no need to worry that such macros might be > incompatible with each other or have strict ordering constraints. > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>I''m happy with this so far as it goes but I was wondering where the original -Wdeclaration-after-statement came from, do we actually mean "-std=c99" or something along those lines? Anyway I''m still ok with saying: Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > tools/libxl/Makefile | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > index f363da2..4e0f3fb 100644 > --- a/tools/libxl/Makefile > +++ b/tools/libxl/Makefile > @@ -11,7 +11,8 @@ MINOR = 0 > XLUMAJOR = 1.0 > XLUMINOR = 0 > > -CFLAGS += -Werror -Wno-format-zero-length -Wmissing-declarations > +CFLAGS += -Werror -Wno-format-zero-length -Wmissing-declarations \ > + -Wno-declaration-after-statement > CFLAGS += -I. -fPIC > > ifeq ($(CONFIG_Linux),y)
Ian Campbell
2011-Dec-07 16:28 UTC
Re: [PATCH 12/15] libxl: Use GC_INIT and GC_FREE everywhere
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> Replace > libxl__gc gc = LIBXL_INIT_GC(ctx); > ... > libxl__free_all(&gc); > with > GC_INIT(ctx); > ... > GC_FREE;I suppose this really relates to the earlier patch which adds these macros but wouldn''t "GC_FREE();" be nicer?> throughout with a couple of perl runes. > > We must then adjust uses of the resulting gc for pointerness, which is > mostly just replacing all occurrences of "&gc" with "gc".BTW I really like this aspect of the change since one big annoyance when making an exiting internal function into an external one (or vice versa) is the need to frob all the uses of gc... Ian.> Also a > couple of unusual uses of LIBXL_INIT_GC needed to be fixed up by hand. > > Here are those runes: > perl -i -pe ''s/\Q libxl__gc gc = LIBXL_INIT_GC(ctx);/ GC_INIT(ctx);/'' tools/libxl/*.c > perl -i -pe ''s/\Q libxl__free_all(&gc);/ GC_FREE;/'' tools/libxl/*.c > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> > --- > tools/libxl/libxl.c | 590 ++++++++++++++++++++-------------------- > tools/libxl/libxl_bootloader.c | 14 +- > tools/libxl/libxl_create.c | 12 +- > tools/libxl/libxl_dom.c | 16 +- > tools/libxl/libxl_pci.c | 34 ++-- > tools/libxl/libxl_qmp.c | 32 +- > tools/libxl/libxl_utils.c | 36 ++-- > 7 files changed, 367 insertions(+), 367 deletions(-) > > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index 7488538..3a8cfe3 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -232,19 +232,19 @@ int libxl__domain_rename(libxl__gc *gc, uint32_t domid, > int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid, > const char *old_name, const char *new_name) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > - rc = libxl__domain_rename(&gc, domid, old_name, new_name, XBT_NULL); > - libxl__free_all(&gc); > + rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL); > + GC_FREE; > return rc; > } > > int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc = 0; > > - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { > + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { > LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Called domain_resume on " > "non-cooperative hvm domain %u", domid); > rc = ERROR_NI; > @@ -264,7 +264,7 @@ int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid) > rc = ERROR_FAIL; > } > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -277,7 +277,7 @@ out: > int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, > libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > struct xs_permissions roperm[2]; > xs_transaction_t t; > char *preserved_name; > @@ -287,27 +287,27 @@ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, > > int rc; > > - preserved_name = libxl__sprintf(&gc, "%s%s", info->name, name_suffix); > + preserved_name = libxl__sprintf(gc, "%s%s", info->name, name_suffix); > if (!preserved_name) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_NOMEM; > } > > - uuid_string = libxl__uuid2string(&gc, new_uuid); > + uuid_string = libxl__uuid2string(gc, new_uuid); > if (!uuid_string) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_NOMEM; > } > > - dom_path = libxl__xs_get_dompath(&gc, domid); > + dom_path = libxl__xs_get_dompath(gc, domid); > if (!dom_path) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > - vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string); > + vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string); > if (!vm_path) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > @@ -323,20 +323,20 @@ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, > xs_mkdir(ctx->xsh, t, vm_path); > xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm)); > > - xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); > - rc = libxl__domain_rename(&gc, domid, info->name, preserved_name, t); > + xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); > + rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t); > if (rc) { > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > - xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); > + xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); > > if (!xs_transaction_end(ctx->xsh, t, 0)) > if (errno == EAGAIN) > goto retry_transaction; > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > @@ -478,16 +478,16 @@ libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm) > int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info, > uint32_t domid, int fd) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > - libxl_domain_type type = libxl__domain_type(&gc, domid); > + GC_INIT(ctx); > + libxl_domain_type type = libxl__domain_type(gc, domid); > int live = info != NULL && info->flags & XL_SUSPEND_LIVE; > int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG; > int rc = 0; > > - rc = libxl__domain_suspend_common(&gc, domid, fd, type, live, debug); > + rc = libxl__domain_suspend_common(gc, domid, fd, type, live, debug); > if (!rc && type == LIBXL_DOMAIN_TYPE_HVM) > - rc = libxl__domain_save_device_model(&gc, domid, fd); > - libxl__free_all(&gc); > + rc = libxl__domain_save_device_model(gc, domid, fd); > + GC_FREE; > return rc; > } > > @@ -517,17 +517,17 @@ int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid, > > int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *path; > char *state; > int ret, rc = 0; > > - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { > - path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d/state", domid); > - state = libxl__xs_read(&gc, XBT_NULL, path); > + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { > + path = libxl__sprintf(gc, "/local/domain/0/device-model/%d/state", domid); > + state = libxl__xs_read(gc, XBT_NULL, path); > if (state != NULL && !strcmp(state, "paused")) { > - libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "continue"); > - libxl__wait_for_device_model(&gc, domid, "running", > + libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/0/device-model/%d/command", domid), "continue"); > + libxl__wait_for_device_model(gc, domid, "running", > NULL, NULL, NULL); > } > } > @@ -536,7 +536,7 @@ int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid) > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unpausing domain %d", domid); > rc = ERROR_FAIL; > } > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -550,42 +550,42 @@ static char *req_table[] = { > > int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *shutdown_path; > char *dom_path; > > if (req > ARRAY_SIZE(req_table)) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_INVAL; > } > > - dom_path = libxl__xs_get_dompath(&gc, domid); > + dom_path = libxl__xs_get_dompath(gc, domid); > if (!dom_path) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > - if (LIBXL__DOMAIN_IS_TYPE(&gc, domid, HVM)) { > + if (LIBXL__DOMAIN_IS_TYPE(gc, domid, HVM)) { > unsigned long pvdriver = 0; > int ret; > ret = xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver); > if (ret<0) { > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting HVM callback IRQ"); > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > if (!pvdriver) { > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "HVM domain without PV drivers:" > " graceful shutdown not possible, use destroy"); > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > } > > - shutdown_path = libxl__sprintf(&gc, "%s/control/shutdown", dom_path); > + shutdown_path = libxl__sprintf(gc, "%s/control/shutdown", dom_path); > xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req])); > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > @@ -607,7 +607,7 @@ int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *wa > > int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int i, rc = -1; > uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid); > > @@ -616,7 +616,7 @@ int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_devic > > for (i = 0; i < num_disks; i++) { > if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", > - libxl__xs_get_dompath(&gc, domid), > + libxl__xs_get_dompath(gc, domid), > libxl__device_disk_dev_number(disks[i].vdev, > NULL, NULL)) < 0) > goto out; > @@ -626,7 +626,7 @@ int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_devic > } > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -680,22 +680,22 @@ int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_even > > int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *path; > char *backend; > char *value; > char backend_type[BACKEND_STRING_SIZE+1]; > > - value = libxl__xs_read(&gc, XBT_NULL, event->path); > + value = libxl__xs_read(gc, XBT_NULL, event->path); > > if (!value || strcmp(value, "eject")) { > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > path = strdup(event->path); > path[strlen(path) - 6] = ''\0''; > - backend = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", path)); > + backend = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend", path)); > > sscanf(backend, > "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE) "[a-z]/%*d/%*d", > @@ -711,19 +711,19 @@ int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event > disk->pdev_path = strdup(""); > disk->format = LIBXL_DISK_FORMAT_EMPTY; > /* this value is returned to the user: do not free right away */ > - disk->vdev = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/dev", backend), NULL); > + disk->vdev = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "%s/dev", backend), NULL); > disk->removable = 1; > disk->readwrite = 0; > disk->is_cdrom = 1; > > free(path); > - libxl__free_all(&gc); > + GC_FREE; > return 1; > } > > int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl_dominfo dominfo; > char *dom_path; > char *vm_path; > @@ -740,40 +740,40 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) > return rc; > } > > - switch (libxl__domain_type(&gc, domid)) { > + switch (libxl__domain_type(gc, domid)) { > case LIBXL_DOMAIN_TYPE_HVM: > dm_present = 1; > break; > case LIBXL_DOMAIN_TYPE_PV: > - pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid)); > + pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/image/device-model-pid", domid)); > dm_present = (pid != NULL); > break; > default: > abort(); > } > > - dom_path = libxl__xs_get_dompath(&gc, domid); > + dom_path = libxl__xs_get_dompath(gc, domid); > if (!dom_path) { > rc = ERROR_FAIL; > goto out; > } > > - if (libxl__device_pci_destroy_all(&gc, domid) < 0) > + if (libxl__device_pci_destroy_all(gc, domid) < 0) > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid); > rc = xc_domain_pause(ctx->xch, domid); > if (rc < 0) { > LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid); > } > if (dm_present) { > - if (libxl__destroy_device_model(&gc, domid) < 0) > + 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); > + libxl__qmp_cleanup(gc, domid); > } > - if (libxl__devices_destroy(&gc, domid, force) < 0) > + if (libxl__devices_destroy(gc, domid, force) < 0) > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_devices_dispose failed for %d", domid); > > - vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path)); > + vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dom_path)); > if (vm_path) > if (!xs_rm(ctx->xsh, XBT_NULL, vm_path)) > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", vm_path); > @@ -781,9 +781,9 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) > if (!xs_rm(ctx->xsh, XBT_NULL, dom_path)) > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", dom_path); > > - xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(&gc, domid)); > + xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid)); > > - libxl__userdata_destroyall(&gc, domid); > + libxl__userdata_destroyall(gc, domid); > > rc = xc_domain_destroy(ctx->xch, domid); > if (rc < 0) { > @@ -793,16 +793,16 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force) > } > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_console_type type) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > - char *p = libxl__sprintf(&gc, "%s/xenconsole", libxl_private_bindir_path()); > - char *domid_s = libxl__sprintf(&gc, "%d", domid); > - char *cons_num_s = libxl__sprintf(&gc, "%d", cons_num); > + GC_INIT(ctx); > + char *p = libxl__sprintf(gc, "%s/xenconsole", libxl_private_bindir_path()); > + char *domid_s = libxl__sprintf(gc, "%d", domid); > + char *cons_num_s = libxl__sprintf(gc, "%d", cons_num); > char *cons_type_s; > > switch (type) { > @@ -819,20 +819,20 @@ int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_conso > execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s, (void *)NULL); > > out: > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm); > int rc; > if (stubdomid) > rc = libxl_console_exec(ctx, stubdomid, > STUBDOM_CONSOLE_SERIAL, LIBXL_CONSOLE_TYPE_PV); > else { > - switch (libxl__domain_type(&gc, domid_vm)) { > + switch (libxl__domain_type(gc, domid_vm)) { > case LIBXL_DOMAIN_TYPE_HVM: > rc = libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSOLE_TYPE_SERIAL); > break; > @@ -843,13 +843,13 @@ int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm) > abort(); > } > } > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > const char *vnc_port; > const char *vnc_listen = NULL, *vnc_pass = NULL; > int port = 0, autopass_fd = -1; > @@ -860,19 +860,19 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) > NULL, > }; > > - vnc_port = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, > + vnc_port = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, > "/local/domain/%d/console/vnc-port", domid)); > if ( vnc_port ) > port = atoi(vnc_port) - 5900; > > - vnc_listen = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, > + vnc_listen = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, > "/local/domain/%d/console/vnc-listen", domid)); > > if ( autopass ) > - vnc_pass = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, > + vnc_pass = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, > "/local/domain/%d/console/vnc-pass", domid)); > > if ( NULL == vnc_listen ) > @@ -881,7 +881,7 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) > if ( (vnc_bin = getenv("VNCVIEWER")) ) > args[0] = vnc_bin; > > - args[1] = libxl__sprintf(&gc, "%s:%d", vnc_listen, port); > + args[1] = libxl__sprintf(gc, "%s:%d", vnc_listen, port); > > if ( vnc_pass ) { > char tmpname[] = "/tmp/vncautopass.XXXXXX"; > @@ -916,7 +916,7 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass) > abort(); > > x_fail: > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > @@ -970,17 +970,17 @@ static int libxl__device_from_disk(libxl__gc *gc, uint32_t domid, > > int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > flexarray_t *front; > flexarray_t *back; > char *dev; > libxl__device device; > int major, minor, rc; > > - rc = libxl__device_disk_set_backend(&gc, disk); > + rc = libxl__device_disk_set_backend(gc, disk); > if (rc) goto out; > > - rc = libxl__device_disk_set_backend(&gc, disk); > + rc = libxl__device_disk_set_backend(gc, disk); > if (rc) goto out; > > front = flexarray_make(16, 1); > @@ -1001,7 +1001,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > goto out_free; > } > > - rc = libxl__device_from_disk(&gc, domid, disk, &device); > + rc = libxl__device_from_disk(gc, domid, disk, &device); > if (rc != 0) { > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported" > " virtual disk identifier %s", disk->vdev); > @@ -1014,7 +1014,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > do_backend_phy: > libxl__device_physdisk_major_minor(dev, &major, &minor); > flexarray_append(back, "physical-device"); > - flexarray_append(back, libxl__sprintf(&gc, "%x:%x", major, minor)); > + flexarray_append(back, libxl__sprintf(gc, "%x:%x", major, minor)); > > flexarray_append(back, "params"); > flexarray_append(back, dev); > @@ -1022,13 +1022,13 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD); > break; > case LIBXL_DISK_BACKEND_TAP: > - dev = libxl__blktap_devpath(&gc, disk->pdev_path, disk->format); > + dev = libxl__blktap_devpath(gc, disk->pdev_path, disk->format); > if (!dev) { > rc = ERROR_FAIL; > goto out_free; > } > flexarray_append(back, "tapdisk-params"); > - flexarray_append(back, libxl__sprintf(&gc, "%s:%s", > + flexarray_append(back, libxl__sprintf(gc, "%s:%s", > libxl__device_disk_string_of_format(disk->format), > disk->pdev_path)); > > @@ -1036,7 +1036,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > goto do_backend_phy; > case LIBXL_DISK_BACKEND_QDISK: > flexarray_append(back, "params"); > - flexarray_append(back, libxl__sprintf(&gc, "%s:%s", > + flexarray_append(back, libxl__sprintf(gc, "%s:%s", > libxl__device_disk_string_of_format(disk->format), disk->pdev_path)); > assert(device.backend_kind == LIBXL__DEVICE_KIND_QDISK); > break; > @@ -1047,15 +1047,15 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > } > > flexarray_append(back, "frontend-id"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); > + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); > flexarray_append(back, "online"); > flexarray_append(back, "1"); > flexarray_append(back, "removable"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", (disk->removable) ? 1 : 0)); > + flexarray_append(back, libxl__sprintf(gc, "%d", (disk->removable) ? 1 : 0)); > flexarray_append(back, "bootable"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); > flexarray_append(back, "state"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); > flexarray_append(back, "dev"); > flexarray_append(back, disk->vdev); > flexarray_append(back, "type"); > @@ -1066,17 +1066,17 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis > flexarray_append(back, disk->is_cdrom ? "cdrom" : "disk"); > > flexarray_append(front, "backend-id"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", disk->backend_domid)); > + flexarray_append(front, libxl__sprintf(gc, "%d", disk->backend_domid)); > flexarray_append(front, "state"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); > flexarray_append(front, "virtual-device"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", device.devid)); > + flexarray_append(front, libxl__sprintf(gc, "%d", device.devid)); > flexarray_append(front, "device-type"); > flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk"); > > - libxl__device_generic_add(&gc, &device, > - libxl__xs_kvs_of_flexarray(&gc, back, back->count), > - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); > + libxl__device_generic_add(gc, &device, > + libxl__xs_kvs_of_flexarray(gc, back, back->count), > + libxl__xs_kvs_of_flexarray(gc, front, front->count)); > > rc = 0; > > @@ -1084,39 +1084,39 @@ out_free: > flexarray_free(back); > flexarray_free(front); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid, > libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_disk(&gc, domid, disk, &device); > + rc = libxl__device_from_disk(gc, domid, disk, &device); > if (rc != 0) goto out; > > - rc = libxl__device_remove(&gc, &device, 1); > + rc = libxl__device_remove(gc, &device, 1); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_disk_destroy(libxl_ctx *ctx, uint32_t domid, > libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_disk(&gc, domid, disk, &device); > + rc = libxl__device_from_disk(gc, domid, disk, &device); > if (rc != 0) goto out; > > - rc = libxl__device_destroy(&gc, &device); > + rc = libxl__device_destroy(gc, &device); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1168,27 +1168,27 @@ static void libxl__device_disk_from_xs_be(libxl__gc *gc, > int libxl_devid_to_device_disk(libxl_ctx *ctx, uint32_t domid, > int devid, libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *dompath, *path; > int rc = ERROR_FAIL; > > libxl_device_disk_init(ctx, disk); > > - dompath = libxl__xs_get_dompath(&gc, domid); > + dompath = libxl__xs_get_dompath(gc, domid); > if (!dompath) { > goto out; > } > - path = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, "%s/device/vbd/%d/backend", > + path = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, "%s/device/vbd/%d/backend", > dompath, devid)); > if (!path) > goto out; > > - libxl__device_disk_from_xs_be(&gc, path, disk); > + libxl__device_disk_from_xs_be(gc, path, disk); > > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1228,22 +1228,22 @@ static int libxl__append_disk_list_of_type(libxl__gc *gc, > > libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl_device_disk *disks = NULL; > int rc; > > *num = 0; > > - rc = libxl__append_disk_list_of_type(&gc, domid, "vbd", &disks, num); > + rc = libxl__append_disk_list_of_type(gc, domid, "vbd", &disks, num); > if (rc) goto out_err; > > - rc = libxl__append_disk_list_of_type(&gc, domid, "tap", &disks, num); > + rc = libxl__append_disk_list_of_type(gc, domid, "tap", &disks, num); > if (rc) goto out_err; > > - rc = libxl__append_disk_list_of_type(&gc, domid, "qdisk", &disks, num); > + rc = libxl__append_disk_list_of_type(gc, domid, "qdisk", &disks, num); > if (rc) goto out_err; > > - libxl__free_all(&gc); > + GC_FREE; > return disks; > > out_err: > @@ -1259,35 +1259,35 @@ out_err: > int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid, > libxl_device_disk *disk, libxl_diskinfo *diskinfo) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *dompath, *diskpath; > char *val; > > - dompath = libxl__xs_get_dompath(&gc, domid); > + dompath = libxl__xs_get_dompath(gc, domid); > diskinfo->devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL); > > /* tap devices entries in xenstore are written as vbd devices. */ > - diskpath = libxl__sprintf(&gc, "%s/device/vbd/%d", dompath, diskinfo->devid); > + diskpath = libxl__sprintf(gc, "%s/device/vbd/%d", dompath, diskinfo->devid); > diskinfo->backend = xs_read(ctx->xsh, XBT_NULL, > - libxl__sprintf(&gc, "%s/backend", diskpath), NULL); > + libxl__sprintf(gc, "%s/backend", diskpath), NULL); > if (!diskinfo->backend) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", diskpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend-id", diskpath)); > diskinfo->backend_id = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", diskpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/state", diskpath)); > diskinfo->state = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", diskpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/event-channel", diskpath)); > diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/ring-ref", diskpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/ring-ref", diskpath)); > diskinfo->rref = val ? strtoul(val, NULL, 10) : -1; > diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL, > - libxl__sprintf(&gc, "%s/frontend", diskinfo->backend), NULL); > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", diskinfo->backend)); > + libxl__sprintf(gc, "%s/frontend", diskinfo->backend), NULL); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/frontend-id", diskinfo->backend)); > diskinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1; > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > @@ -1331,12 +1331,12 @@ out: > > char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *dev = NULL; > char *ret = NULL; > int rc; > > - rc = libxl__device_disk_set_backend(&gc, disk); > + rc = libxl__device_disk_set_backend(gc, disk); > if (rc) goto out; > > switch (disk->backend) { > @@ -1355,7 +1355,7 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) > dev = disk->pdev_path; > break; > case LIBXL_DISK_FORMAT_VHD: > - dev = libxl__blktap_devpath(&gc, disk->pdev_path, > + dev = libxl__blktap_devpath(gc, disk->pdev_path, > disk->format); > break; > case LIBXL_DISK_FORMAT_QCOW: > @@ -1386,7 +1386,7 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk) > out: > if (dev != NULL) > ret = strdup(dev); > - libxl__free_all(&gc); > + GC_FREE; > return ret; > } > > @@ -1448,7 +1448,7 @@ static int libxl__device_from_nic(libxl__gc *gc, uint32_t domid, > > int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > flexarray_t *front; > flexarray_t *back; > libxl__device device; > @@ -1467,59 +1467,59 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) > } > > if (nic->devid == -1) { > - if (!(dompath = libxl__xs_get_dompath(&gc, domid))) { > + if (!(dompath = libxl__xs_get_dompath(gc, domid))) { > rc = ERROR_FAIL; > goto out_free; > } > - if (!(l = libxl__xs_directory(&gc, XBT_NULL, > - libxl__sprintf(&gc, "%s/device/vif", dompath), &nb))) { > + if (!(l = libxl__xs_directory(gc, XBT_NULL, > + libxl__sprintf(gc, "%s/device/vif", dompath), &nb))) { > nic->devid = 0; > } else { > nic->devid = strtoul(l[nb - 1], NULL, 10) + 1; > } > } > > - rc = libxl__device_from_nic(&gc, domid, nic, &device); > + rc = libxl__device_from_nic(gc, domid, nic, &device); > if ( rc != 0 ) goto out_free; > > flexarray_append(back, "frontend-id"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); > + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); > flexarray_append(back, "online"); > flexarray_append(back, "1"); > flexarray_append(back, "state"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); > if (nic->script) { > flexarray_append(back, "script"); > flexarray_append(back, nic->script[0]==''/'' ? nic->script > - : libxl__sprintf(&gc, "%s/%s", > + : libxl__sprintf(gc, "%s/%s", > libxl_xen_script_dir_path(), > nic->script)); > } > flexarray_append(back, "mac"); > - flexarray_append(back,libxl__sprintf(&gc, > + flexarray_append(back,libxl__sprintf(gc, > LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); > if (nic->ip) { > flexarray_append(back, "ip"); > - flexarray_append(back, libxl__strdup(&gc, nic->ip)); > + flexarray_append(back, libxl__strdup(gc, nic->ip)); > } > > flexarray_append(back, "bridge"); > - flexarray_append(back, libxl__strdup(&gc, nic->bridge)); > + flexarray_append(back, libxl__strdup(gc, nic->bridge)); > flexarray_append(back, "handle"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", nic->devid)); > + flexarray_append(back, libxl__sprintf(gc, "%d", nic->devid)); > > flexarray_append(front, "backend-id"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", nic->backend_domid)); > + flexarray_append(front, libxl__sprintf(gc, "%d", nic->backend_domid)); > flexarray_append(front, "state"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); > flexarray_append(front, "handle"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", nic->devid)); > + flexarray_append(front, libxl__sprintf(gc, "%d", nic->devid)); > flexarray_append(front, "mac"); > - flexarray_append(front, libxl__sprintf(&gc, > + flexarray_append(front, libxl__sprintf(gc, > LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); > - libxl__device_generic_add(&gc, &device, > - libxl__xs_kvs_of_flexarray(&gc, back, back->count), > - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); > + libxl__device_generic_add(gc, &device, > + libxl__xs_kvs_of_flexarray(gc, back, back->count), > + libxl__xs_kvs_of_flexarray(gc, front, front->count)); > > /* FIXME: wait for plug */ > rc = 0; > @@ -1527,39 +1527,39 @@ out_free: > flexarray_free(back); > flexarray_free(front); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid, > libxl_device_nic *nic) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_nic(&gc, domid, nic, &device); > + rc = libxl__device_from_nic(gc, domid, nic, &device); > if (rc != 0) goto out; > > - rc = libxl__device_remove(&gc, &device, 1); > + rc = libxl__device_remove(gc, &device, 1); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid, > libxl_device_nic *nic) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_nic(&gc, domid, nic, &device); > + rc = libxl__device_from_nic(gc, domid, nic, &device); > if (rc != 0) goto out; > > - rc = libxl__device_destroy(&gc, &device); > + rc = libxl__device_destroy(gc, &device); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1607,26 +1607,26 @@ static void libxl__device_nic_from_xs_be(libxl__gc *gc, > int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid, > int devid, libxl_device_nic *nic) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *dompath, *path; > int rc = ERROR_FAIL; > > memset(nic, 0, sizeof (libxl_device_nic)); > - dompath = libxl__xs_get_dompath(&gc, domid); > + dompath = libxl__xs_get_dompath(gc, domid); > if (!dompath) > goto out; > > - path = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, "%s/device/vif/%d/backend", > + path = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, "%s/device/vif/%d/backend", > dompath, devid)); > if (!path) > goto out; > > - libxl__device_nic_from_xs_be(&gc, path, nic); > + libxl__device_nic_from_xs_be(gc, path, nic); > > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1665,16 +1665,16 @@ static int libxl__append_nic_list_of_type(libxl__gc *gc, > > libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int *num) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl_device_nic *nics = NULL; > int rc; > > *num = 0; > > - rc = libxl__append_nic_list_of_type(&gc, domid, "vif", &nics, num); > + rc = libxl__append_nic_list_of_type(gc, domid, "vif", &nics, num); > if (rc) goto out_err; > > - libxl__free_all(&gc); > + GC_FREE; > return nics; > > out_err: > @@ -1690,36 +1690,36 @@ out_err: > int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid, > libxl_device_nic *nic, libxl_nicinfo *nicinfo) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *dompath, *nicpath; > char *val; > > - dompath = libxl__xs_get_dompath(&gc, domid); > + dompath = libxl__xs_get_dompath(gc, domid); > nicinfo->devid = nic->devid; > > - nicpath = libxl__sprintf(&gc, "%s/device/vif/%d", dompath, nicinfo->devid); > + nicpath = libxl__sprintf(gc, "%s/device/vif/%d", dompath, nicinfo->devid); > nicinfo->backend = xs_read(ctx->xsh, XBT_NULL, > - libxl__sprintf(&gc, "%s/backend", nicpath), NULL); > + libxl__sprintf(gc, "%s/backend", nicpath), NULL); > if (!nicinfo->backend) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", nicpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend-id", nicpath)); > nicinfo->backend_id = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", nicpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/state", nicpath)); > nicinfo->state = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", nicpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/event-channel", nicpath)); > nicinfo->evtch = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/tx-ring-ref", nicpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/tx-ring-ref", nicpath)); > nicinfo->rref_tx = val ? strtoul(val, NULL, 10) : -1; > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/rx-ring-ref", nicpath)); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/rx-ring-ref", nicpath)); > nicinfo->rref_rx = val ? strtoul(val, NULL, 10) : -1; > nicinfo->frontend = xs_read(ctx->xsh, XBT_NULL, > - libxl__sprintf(&gc, "%s/frontend", nicinfo->backend), NULL); > - val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", nicinfo->backend)); > + libxl__sprintf(gc, "%s/frontend", nicinfo->backend), NULL); > + val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/frontend-id", nicinfo->backend)); > nicinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1; > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > @@ -1825,7 +1825,7 @@ static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid, > > int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > flexarray_t *front; > flexarray_t *back; > libxl__device device; > @@ -1842,64 +1842,64 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) > goto out_free; > } > > - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); > + rc = libxl__device_from_vkb(gc, domid, vkb, &device); > if (rc != 0) goto out_free; > > flexarray_append(back, "frontend-id"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", domid)); > + flexarray_append(back, libxl__sprintf(gc, "%d", domid)); > flexarray_append(back, "online"); > flexarray_append(back, "1"); > flexarray_append(back, "state"); > - flexarray_append(back, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(back, libxl__sprintf(gc, "%d", 1)); > flexarray_append(back, "domain"); > - flexarray_append(back, libxl__domid_to_name(&gc, domid)); > + flexarray_append(back, libxl__domid_to_name(gc, domid)); > > flexarray_append(front, "backend-id"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", vkb->backend_domid)); > + flexarray_append(front, libxl__sprintf(gc, "%d", vkb->backend_domid)); > flexarray_append(front, "state"); > - flexarray_append(front, libxl__sprintf(&gc, "%d", 1)); > + flexarray_append(front, libxl__sprintf(gc, "%d", 1)); > > - libxl__device_generic_add(&gc, &device, > - libxl__xs_kvs_of_flexarray(&gc, back, back->count), > - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); > + libxl__device_generic_add(gc, &device, > + libxl__xs_kvs_of_flexarray(gc, back, back->count), > + libxl__xs_kvs_of_flexarray(gc, front, front->count)); > rc = 0; > out_free: > flexarray_free(back); > flexarray_free(front); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t domid, > libxl_device_vkb *vkb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); > + rc = libxl__device_from_vkb(gc, domid, vkb, &device); > if (rc != 0) goto out; > > - rc = libxl__device_remove(&gc, &device, 1); > + rc = libxl__device_remove(gc, &device, 1); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid, > libxl_device_vkb *vkb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_vkb(&gc, domid, vkb, &device); > + rc = libxl__device_from_vkb(gc, domid, vkb, &device); > if (rc != 0) goto out; > > - rc = libxl__device_destroy(&gc, &device); > + rc = libxl__device_destroy(gc, &device); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1935,7 +1935,7 @@ static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid, > > int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > flexarray_t *front; > flexarray_t *back; > libxl__device device; > @@ -1952,20 +1952,20 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) > goto out_free; > } > > - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); > + rc = libxl__device_from_vfb(gc, domid, vfb, &device); > if (rc != 0) goto out_free; > > - flexarray_append_pair(back, "frontend-id", libxl__sprintf(&gc, "%d", domid)); > + flexarray_append_pair(back, "frontend-id", libxl__sprintf(gc, "%d", domid)); > flexarray_append_pair(back, "online", "1"); > - flexarray_append_pair(back, "state", libxl__sprintf(&gc, "%d", 1)); > - flexarray_append_pair(back, "domain", libxl__domid_to_name(&gc, domid)); > - flexarray_append_pair(back, "vnc", libxl__sprintf(&gc, "%d", vfb->vnc)); > + flexarray_append_pair(back, "state", libxl__sprintf(gc, "%d", 1)); > + flexarray_append_pair(back, "domain", libxl__domid_to_name(gc, domid)); > + flexarray_append_pair(back, "vnc", libxl__sprintf(gc, "%d", vfb->vnc)); > flexarray_append_pair(back, "vnclisten", vfb->vnclisten); > flexarray_append_pair(back, "vncpasswd", vfb->vncpasswd); > - flexarray_append_pair(back, "vncdisplay", libxl__sprintf(&gc, "%d", vfb->vncdisplay)); > - flexarray_append_pair(back, "vncunused", libxl__sprintf(&gc, "%d", vfb->vncunused)); > - flexarray_append_pair(back, "sdl", libxl__sprintf(&gc, "%d", vfb->sdl)); > - flexarray_append_pair(back, "opengl", libxl__sprintf(&gc, "%d", vfb->opengl)); > + flexarray_append_pair(back, "vncdisplay", libxl__sprintf(gc, "%d", vfb->vncdisplay)); > + flexarray_append_pair(back, "vncunused", libxl__sprintf(gc, "%d", vfb->vncunused)); > + flexarray_append_pair(back, "sdl", libxl__sprintf(gc, "%d", vfb->sdl)); > + flexarray_append_pair(back, "opengl", libxl__sprintf(gc, "%d", vfb->opengl)); > if (vfb->xauthority) { > flexarray_append_pair(back, "xauthority", vfb->xauthority); > } > @@ -1973,50 +1973,50 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) > flexarray_append_pair(back, "display", vfb->display); > } > > - flexarray_append_pair(front, "backend-id", libxl__sprintf(&gc, "%d", vfb->backend_domid)); > - flexarray_append_pair(front, "state", libxl__sprintf(&gc, "%d", 1)); > + flexarray_append_pair(front, "backend-id", libxl__sprintf(gc, "%d", vfb->backend_domid)); > + flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1)); > > - libxl__device_generic_add(&gc, &device, > - libxl__xs_kvs_of_flexarray(&gc, back, back->count), > - libxl__xs_kvs_of_flexarray(&gc, front, front->count)); > + libxl__device_generic_add(gc, &device, > + libxl__xs_kvs_of_flexarray(gc, back, back->count), > + libxl__xs_kvs_of_flexarray(gc, front, front->count)); > rc = 0; > out_free: > flexarray_free(front); > flexarray_free(back); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t domid, > libxl_device_vfb *vfb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); > + rc = libxl__device_from_vfb(gc, domid, vfb, &device); > if (rc != 0) goto out; > > - rc = libxl__device_remove(&gc, &device, 1); > + rc = libxl__device_remove(gc, &device, 1); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid, > libxl_device_vfb *vfb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl__device device; > int rc; > > - rc = libxl__device_from_vfb(&gc, domid, vfb, &device); > + rc = libxl__device_from_vfb(gc, domid, vfb, &device); > if (rc != 0) goto out; > > - rc = libxl__device_destroy(&gc, &device); > + rc = libxl__device_destroy(gc, &device); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -2024,13 +2024,13 @@ out: > > int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *mem, *endptr; > uint32_t memorykb; > - char *dompath = libxl__xs_get_dompath(&gc, domid); > + char *dompath = libxl__xs_get_dompath(gc, domid); > int rc = 1; > > - mem = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/memory/target", dompath)); > + mem = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/memory/target", dompath)); > if (!mem) { > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot get memory info from %s/memory/target\n", dompath); > goto out; > @@ -2055,7 +2055,7 @@ int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb) > > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -2163,12 +2163,12 @@ retry: > int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid, > int32_t target_memkb, int relative, int enforce) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc = 1, abort = 0; > uint32_t memorykb = 0, videoram = 0; > uint32_t current_target_memkb = 0, new_target_memkb = 0; > char *memmax, *endptr, *videoram_s = NULL, *target = NULL; > - char *dompath = libxl__xs_get_dompath(&gc, domid); > + char *dompath = libxl__xs_get_dompath(gc, domid); > xc_domaininfo_t info; > libxl_dominfo ptr; > char *uuid; > @@ -2177,11 +2177,11 @@ int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid, > retry_transaction: > t = xs_transaction_start(ctx->xsh); > > - target = libxl__xs_read(&gc, t, libxl__sprintf(&gc, > + target = libxl__xs_read(gc, t, libxl__sprintf(gc, > "%s/memory/target", dompath)); > if (!target && !domid) { > xs_transaction_end(ctx->xsh, t, 1); > - rc = libxl__fill_dom0_memory_info(&gc, ¤t_target_memkb); > + rc = libxl__fill_dom0_memory_info(gc, ¤t_target_memkb); > if (rc < 0) { > abort = 1; > goto out; > @@ -2203,7 +2203,7 @@ retry_transaction: > goto out; > } > } > - memmax = libxl__xs_read(&gc, t, libxl__sprintf(&gc, > + memmax = libxl__xs_read(gc, t, libxl__sprintf(gc, > "%s/memory/static-max", dompath)); > if (!memmax) { > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, > @@ -2243,7 +2243,7 @@ retry_transaction: > abort = 1; > goto out; > } > - videoram_s = libxl__xs_read(&gc, t, libxl__sprintf(&gc, > + videoram_s = libxl__xs_read(gc, t, libxl__sprintf(gc, > "%s/memory/videoram", dompath)); > videoram = videoram_s ? atoi(videoram_s) : 0; > > @@ -2272,7 +2272,7 @@ retry_transaction: > goto out; > } > > - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/memory/target", > + libxl__xs_write(gc, t, libxl__sprintf(gc, "%s/memory/target", > dompath), "%"PRIu32, new_target_memkb); > rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info); > if (rc != 1 || info.domain != domid) { > @@ -2280,8 +2280,8 @@ retry_transaction: > goto out; > } > xcinfo2xlinfo(&info, &ptr); > - uuid = libxl__uuid2string(&gc, ptr.uuid); > - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/vm/%s/memory", uuid), > + uuid = libxl__uuid2string(gc, ptr.uuid); > + libxl__xs_write(gc, t, libxl__sprintf(gc, "/vm/%s/memory", uuid), > "%"PRIu32, new_target_memkb / 1024); > > out: > @@ -2289,22 +2289,22 @@ out: > if (errno == EAGAIN) > goto retry_transaction; > > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc = 1; > char *target = NULL, *endptr = NULL; > - char *dompath = libxl__xs_get_dompath(&gc, domid); > + char *dompath = libxl__xs_get_dompath(gc, domid); > uint32_t target_memkb; > > - target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, > + target = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, > "%s/memory/target", dompath)); > if (!target && !domid) { > - rc = libxl__fill_dom0_memory_info(&gc, &target_memkb); > + rc = libxl__fill_dom0_memory_info(gc, &target_memkb); > if (rc < 0) > goto out; > } else if (!target) { > @@ -2325,14 +2325,14 @@ int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target > rc = 0; > > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info, > libxl_device_model_info *dm_info, uint32_t *need_memkb) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc = ERROR_INVAL; > *need_memkb = b_info->target_memkb; > switch (b_info->type) { > @@ -2351,7 +2351,7 @@ int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info, > *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024)); > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > > } > @@ -2361,12 +2361,12 @@ int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb) > int rc = 0; > libxl_physinfo info; > uint32_t freemem_slack; > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > > rc = libxl_get_physinfo(ctx, &info); > if (rc < 0) > goto out; > - rc = libxl__get_free_memory_slack(&gc, &freemem_slack); > + rc = libxl__get_free_memory_slack(gc, &freemem_slack); > if (rc < 0) > goto out; > > @@ -2376,7 +2376,7 @@ int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb) > *memkb = 0; > > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -2386,9 +2386,9 @@ int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t > int rc = 0; > libxl_physinfo info; > uint32_t freemem_slack; > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > > - rc = libxl__get_free_memory_slack(&gc, &freemem_slack); > + rc = libxl__get_free_memory_slack(gc, &freemem_slack); > if (rc < 0) > goto out; > while (wait_secs > 0) { > @@ -2405,7 +2405,7 @@ int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t > rc = ERROR_NOMEM; > > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -2631,7 +2631,7 @@ int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid, > > int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_cpumap *cpumap) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl_dominfo info; > char *dompath; > xs_transaction_t t; > @@ -2641,14 +2641,14 @@ int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_cpumap *cpumap) > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list"); > goto out; > } > - if (!(dompath = libxl__xs_get_dompath(&gc, domid))) > + if (!(dompath = libxl__xs_get_dompath(gc, domid))) > goto out; > > retry_transaction: > t = xs_transaction_start(ctx->xsh); > for (i = 0; i <= info.vcpu_max_id; i++) > - libxl__xs_write(&gc, t, > - libxl__sprintf(&gc, "%s/cpu/%u/availability", dompath, i), > + libxl__xs_write(gc, t, > + libxl__sprintf(gc, "%s/cpu/%u/availability", dompath, i), > "%s", libxl_cpumap_test(cpumap, i) ? "online" : "offline"); > if (!xs_transaction_end(ctx->xsh, t, 0)) { > if (errno == EAGAIN) > @@ -2656,7 +2656,7 @@ retry_transaction: > } else > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -2776,12 +2776,12 @@ int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, char *trigger_name, uint3 > > int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > - char *dompath = libxl__xs_get_dompath(&gc, domid); > + GC_INIT(ctx); > + char *dompath = libxl__xs_get_dompath(gc, domid); > > - libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/control/sysrq", dompath), "%c", sysrq); > + libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/control/sysrq", dompath), "%c", sysrq); > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > @@ -2868,15 +2868,15 @@ void libxl_xen_console_read_finish(libxl_ctx *ctx, > > uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > - char *dompath = libxl__xs_get_dompath(&gc, domid); > + GC_INIT(ctx); > + char *dompath = libxl__xs_get_dompath(gc, domid); > char *vm_path, *start_time; > uint32_t ret; > > vm_path = libxl__xs_read( > - &gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dompath)); > + gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dompath)); > start_time = libxl__xs_read( > - &gc, XBT_NULL, libxl__sprintf(&gc, "%s/start_time", vm_path)); > + gc, XBT_NULL, libxl__sprintf(gc, "%s/start_time", vm_path)); > if (start_time == NULL) { > LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1, > "Can''t get start time of domain ''%d''", domid); > @@ -2884,7 +2884,7 @@ uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid) > }else{ > ret = strtoul(start_time, NULL, 10); > } > - libxl__free_all(&gc); > + GC_FREE; > return ret; > } > > @@ -3037,15 +3037,15 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, > libxl_cpumap cpumap, libxl_uuid *uuid, > uint32_t *poolid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > int i; > xs_transaction_t t; > char *uuid_string; > > - uuid_string = libxl__uuid2string(&gc, *uuid); > + uuid_string = libxl__uuid2string(gc, *uuid); > if (!uuid_string) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_NOMEM; > } > > @@ -3053,7 +3053,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, > if (rc) { > LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, > "Could not create cpupool"); > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > @@ -3064,7 +3064,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, > LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, > "Error moving cpu to cpupool"); > libxl_cpupool_destroy(ctx, *poolid); > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > } > @@ -3072,16 +3072,16 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, > for (;;) { > t = xs_transaction_start(ctx->xsh); > > - xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/pool/%d", *poolid)); > - libxl__xs_write(&gc, t, > - libxl__sprintf(&gc, "/local/pool/%d/uuid", *poolid), > + xs_mkdir(ctx->xsh, t, libxl__sprintf(gc, "/local/pool/%d", *poolid)); > + libxl__xs_write(gc, t, > + libxl__sprintf(gc, "/local/pool/%d/uuid", *poolid), > "%s", uuid_string); > - libxl__xs_write(&gc, t, > - libxl__sprintf(&gc, "/local/pool/%d/name", *poolid), > + libxl__xs_write(gc, t, > + libxl__sprintf(gc, "/local/pool/%d/name", *poolid), > "%s", name); > > if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) { > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > } > @@ -3089,7 +3089,7 @@ int libxl_create_cpupool(libxl_ctx *ctx, const char *name, int schedid, > > int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc, i; > xc_cpupoolinfo_t *info; > xs_transaction_t t; > @@ -3097,7 +3097,7 @@ int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) > > info = xc_cpupool_getinfo(ctx->xch, poolid); > if (info == NULL) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_NOMEM; > } > > @@ -3131,7 +3131,7 @@ int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid) > for (;;) { > t = xs_transaction_start(ctx->xsh); > > - xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/pool/%d", poolid)); > + xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "/local/pool/%d", poolid)); > > if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) > break; > @@ -3143,21 +3143,21 @@ out1: > libxl_cpumap_dispose(&cpumap); > out: > xc_cpupool_infofree(ctx->xch, info); > - libxl__free_all(&gc); > + GC_FREE; > > return rc; > } > > int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > xs_transaction_t t; > xc_cpupoolinfo_t *info; > int rc; > > info = xc_cpupool_getinfo(ctx->xch, poolid); > if (info == NULL) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_NOMEM; > } > > @@ -3170,8 +3170,8 @@ int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) > for (;;) { > t = xs_transaction_start(ctx->xsh); > > - libxl__xs_write(&gc, t, > - libxl__sprintf(&gc, "/local/pool/%d/name", poolid), > + libxl__xs_write(gc, t, > + libxl__sprintf(gc, "/local/pool/%d/name", poolid), > "%s", name); > > if (xs_transaction_end(ctx->xsh, t, 0)) > @@ -3186,7 +3186,7 @@ int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid) > > out: > xc_cpupool_infofree(ctx->xch, info); > - libxl__free_all(&gc); > + GC_FREE; > > return rc; > } > @@ -3293,16 +3293,16 @@ out: > > int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > char *dom_path; > char *vm_path; > char *poolname; > xs_transaction_t t; > > - dom_path = libxl__xs_get_dompath(&gc, domid); > + dom_path = libxl__xs_get_dompath(gc, domid); > if (!dom_path) { > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > @@ -3310,26 +3310,26 @@ int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid) > if (rc) { > LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, > "Error moving domain to cpupool"); > - libxl__free_all(&gc); > + GC_FREE; > return ERROR_FAIL; > } > > for (;;) { > t = xs_transaction_start(ctx->xsh); > > - poolname = libxl__cpupoolid_to_name(&gc, poolid); > - vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path)); > + poolname = libxl__cpupoolid_to_name(gc, poolid); > + vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", dom_path)); > if (!vm_path) > break; > > - libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), > + libxl__xs_write(gc, t, libxl__sprintf(gc, "%s/pool_name", vm_path), > "%s", poolname); > > if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) > break; > } > > - libxl__free_all(&gc); > + GC_FREE; > return 0; > } > > diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c > index b8399a1..ce83b8e 100644 > --- a/tools/libxl/libxl_bootloader.c > +++ b/tools/libxl/libxl_bootloader.c > @@ -328,7 +328,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, > libxl_device_disk *disk, > uint32_t domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int ret, rc = 0; > char *fifo = NULL; > char *diskpath = NULL; > @@ -388,7 +388,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, > goto out_close; > } > > - args = make_bootloader_args(&gc, info, domid, fifo, diskpath); > + args = make_bootloader_args(gc, info, domid, fifo, diskpath); > if (args == NULL) { > rc = ERROR_NOMEM; > goto out_close; > @@ -411,8 +411,8 @@ int libxl_run_bootloader(libxl_ctx *ctx, > goto out_close; > } > > - dom_console_xs_path = libxl__sprintf(&gc, "%s/console/tty", libxl__xs_get_dompath(&gc, domid)); > - libxl__xs_write(&gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path); > + dom_console_xs_path = libxl__sprintf(gc, "%s/console/tty", libxl__xs_get_dompath(gc, domid)); > + libxl__xs_write(gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path); > > pid = fork_exec_bootloader(&bootloader_fd, info->u.pv.bootloader, args); > if (pid < 0) { > @@ -435,7 +435,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, > > fcntl(fifo_fd, F_SETFL, O_NDELAY); > > - blout = bootloader_interact(&gc, xenconsoled_fd, bootloader_fd, fifo_fd); > + blout = bootloader_interact(gc, xenconsoled_fd, bootloader_fd, fifo_fd); > if (blout == NULL) { > goto out_close; > } > @@ -445,7 +445,7 @@ int libxl_run_bootloader(libxl_ctx *ctx, > goto out_close; > } > > - parse_bootloader_result(&gc, info, blout); > + parse_bootloader_result(gc, info, blout); > > rc = 0; > out_close: > @@ -472,7 +472,7 @@ out_close: > free(args); > > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c > index ccb56c7..69f10fe 100644 > --- a/tools/libxl/libxl_create.c > +++ b/tools/libxl/libxl_create.c > @@ -670,20 +670,20 @@ error_out: > int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config, > libxl_console_ready cb, void *priv, uint32_t *domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > - rc = do_domain_create(&gc, d_config, cb, priv, domid, -1); > - libxl__free_all(&gc); > + rc = do_domain_create(gc, d_config, cb, priv, domid, -1); > + GC_FREE; > return rc; > } > > int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, > libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > - rc = do_domain_create(&gc, d_config, cb, priv, domid, restore_fd); > - libxl__free_all(&gc); > + rc = do_domain_create(gc, d_config, cb, priv, domid, restore_fd); > + GC_FREE; > return rc; > } > > diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c > index 96098de..b1ff967 100644 > --- a/tools/libxl/libxl_dom.c > +++ b/tools/libxl/libxl_dom.c > @@ -730,7 +730,7 @@ int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid, > const char *userdata_userid, > const uint8_t *data, int datalen) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > const char *filename; > const char *newfilename; > int e, rc; > @@ -738,18 +738,18 @@ int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid, > FILE *f = NULL; > size_t rs; > > - filename = userdata_path(&gc, domid, userdata_userid, "d"); > + filename = userdata_path(gc, domid, userdata_userid, "d"); > if (!filename) { > rc = ERROR_NOMEM; > goto out; > } > > if (!datalen) { > - rc = userdata_delete(&gc, filename); > + rc = userdata_delete(gc, filename); > goto out; > } > > - newfilename = userdata_path(&gc, domid, userdata_userid, "n"); > + newfilename = userdata_path(gc, domid, userdata_userid, "n"); > if (!newfilename) { > rc = ERROR_NOMEM; > goto out; > @@ -791,7 +791,7 @@ err: > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot write %s for %s", > newfilename, filename); > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -799,13 +799,13 @@ int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid, > const char *userdata_userid, > uint8_t **data_r, int *datalen_r) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > const char *filename; > int e, rc; > int datalen = 0; > void *data = 0; > > - filename = userdata_path(&gc, domid, userdata_userid, "d"); > + filename = userdata_path(gc, domid, userdata_userid, "d"); > if (!filename) { > rc = ERROR_NOMEM; > goto out; > @@ -827,7 +827,7 @@ int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid, > if (datalen_r) *datalen_r = datalen; > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c > index 63c3050..120c239 100644 > --- a/tools/libxl/libxl_pci.c > +++ b/tools/libxl/libxl_pci.c > @@ -483,7 +483,7 @@ static int is_assigned(libxl_device_pci *assigned, int num_assigned, > > libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > libxl_device_pci *pcidevs = NULL, *new, *assigned; > struct dirent *de; > DIR *dir; > @@ -491,7 +491,7 @@ libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) > > *num = 0; > > - rc = get_all_assigned_devices(&gc, &assigned, &num_assigned); > + rc = get_all_assigned_devices(gc, &assigned, &num_assigned); > if ( rc ) > goto out; > > @@ -528,7 +528,7 @@ libxl_device_pci *libxl_device_pci_list_assignable(libxl_ctx *ctx, int *num) > out_closedir: > closedir(dir); > out: > - libxl__free_all(&gc); > + GC_FREE; > return pcidevs; > } > > @@ -782,10 +782,10 @@ static int libxl__device_pci_reset(libxl__gc *gc, unsigned int domain, unsigned > > int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > - rc = libxl__device_pci_add(&gc, domid, pcidev, 0); > - libxl__free_all(&gc); > + rc = libxl__device_pci_add(gc, domid, pcidev, 0); > + GC_FREE; > return rc; > } > > @@ -1057,24 +1057,24 @@ out: > > int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > > - rc = libxl__device_pci_remove_common(&gc, domid, pcidev, 0); > + rc = libxl__device_pci_remove_common(gc, domid, pcidev, 0); > > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > int libxl_device_pci_destroy(libxl_ctx *ctx, uint32_t domid, > libxl_device_pci *pcidev) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > int rc; > > - rc = libxl__device_pci_remove_common(&gc, domid, pcidev, 1); > + rc = libxl__device_pci_remove_common(gc, domid, pcidev, 1); > > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > @@ -1115,15 +1115,15 @@ static void libxl__device_pci_from_xs_be(libxl__gc *gc, > > libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int *num) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *be_path, *num_devs; > int n, i; > libxl_device_pci *pcidevs = NULL; > > *num = 0; > > - be_path = libxl__sprintf(&gc, "%s/backend/pci/%d/0", libxl__xs_get_dompath(&gc, 0), domid); > - num_devs = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/num_devs", be_path)); > + be_path = libxl__sprintf(gc, "%s/backend/pci/%d/0", libxl__xs_get_dompath(gc, 0), domid); > + num_devs = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/num_devs", be_path)); > if (!num_devs) > goto out; > > @@ -1131,11 +1131,11 @@ libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int *num > pcidevs = calloc(n, sizeof(libxl_device_pci)); > > for (i = 0; i < n; i++) > - libxl__device_pci_from_xs_be(&gc, be_path, pcidevs + i, i); > + libxl__device_pci_from_xs_be(gc, be_path, pcidevs + i, i); > > *num = n; > out: > - libxl__free_all(&gc); > + GC_FREE; > return pcidevs; > } > > diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c > index c7696d7..60af98c 100644 > --- a/tools/libxl/libxl_qmp.c > +++ b/tools/libxl/libxl_qmp.c > @@ -94,7 +94,7 @@ static int store_serial_port_info(libxl__qmp_handler *qmp, > const char *chardev, > int port) > { > - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); > + GC_INIT(qmp->ctx); > char *path = NULL; > int ret = 0; > > @@ -102,12 +102,12 @@ static int store_serial_port_info(libxl__qmp_handler *qmp, > return 0; > } > > - path = libxl__xs_get_dompath(&gc, qmp->domid); > - path = libxl__sprintf(&gc, "%s/serial/%d/tty", path, port); > + 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); > + ret = libxl__xs_write(gc, XBT_NULL, path, "%s", chardev + 4); > > - libxl__free_all(&gc); > + GC_FREE; > return ret; > } > > @@ -521,7 +521,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, > { > int id = 0; > int ret = 0; > - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); > + GC_INIT(qmp->ctx); > qmp_request_context context = { .rc = 0 }; > > id = qmp_send(qmp, cmd, args, callback, opaque, &context); > @@ -531,7 +531,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, > qmp->wait_for_id = id; > > while (qmp->wait_for_id == id) { > - if ((ret = qmp_next(&gc, qmp)) < 0) { > + if ((ret = qmp_next(gc, qmp)) < 0) { > break; > } > } > @@ -540,7 +540,7 @@ static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd, > ret = context.rc; > } > > - libxl__free_all(&gc); > + GC_FREE; > > return ret; > } > @@ -559,15 +559,15 @@ 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); > + GC_INIT(ctx); > > qmp = qmp_init_handler(ctx, domid); > > - qmp_socket = libxl__sprintf(&gc, "%s/qmp-libxl-%d", > + 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); > + GC_FREE; > qmp_free_handler(qmp); > return NULL; > } > @@ -576,12 +576,12 @@ libxl__qmp_handler *libxl__qmp_initialize(libxl_ctx *ctx, uint32_t domid) > > /* Wait for the response to qmp_capabilities */ > while (!qmp->connected) { > - if ((ret = qmp_next(&gc, qmp)) < 0) { > + if ((ret = qmp_next(gc, qmp)) < 0) { > break; > } > } > > - libxl__free_all(&gc); > + GC_FREE; > if (!qmp->connected) { > LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to connect to QMP"); > libxl__qmp_close(qmp); > @@ -626,9 +626,9 @@ static int pci_add_callback(libxl__qmp_handler *qmp, > { > libxl_device_pci *pcidev = opaque; > const libxl__json_object *bus = NULL; > - libxl__gc gc = LIBXL_INIT_GC(qmp->ctx); > + GC_INIT(qmp->ctx); > int i, j, rc = -1; > - char *asked_id = libxl__sprintf(&gc, PCI_PT_QDEV_ID, > + char *asked_id = libxl__sprintf(gc, PCI_PT_QDEV_ID, > pcidev->bus, pcidev->dev, pcidev->func); > > for (i = 0; (bus = libxl__json_array_get(response, i)); i++) { > @@ -665,7 +665,7 @@ static int pci_add_callback(libxl__qmp_handler *qmp, > > > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c > index f1f2a6d..d36c737 100644 > --- a/tools/libxl/libxl_utils.c > +++ b/tools/libxl/libxl_utils.c > @@ -186,29 +186,29 @@ char *libxl_schedid_to_name(libxl_ctx *ctx, int schedid) > > int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char * stubdom_id_s; > int ret; > > - stubdom_id_s = libxl__xs_read(&gc, XBT_NULL, > - libxl__sprintf(&gc, "%s/image/device-model-domid", > - libxl__xs_get_dompath(&gc, guest_domid))); > + stubdom_id_s = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, "%s/image/device-model-domid", > + libxl__xs_get_dompath(gc, guest_domid))); > if (stubdom_id_s) > ret = atoi(stubdom_id_s); > else > ret = 0; > - libxl__free_all(&gc); > + GC_FREE; > return ret; > } > > int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > char *target, *endptr; > uint32_t value; > int ret = 0; > > - target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid))); > + target = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/target", libxl__xs_get_dompath(gc, domid))); > if (!target) > goto out; > value = strtol(target, &endptr, 10); > @@ -218,7 +218,7 @@ int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid) > *target_domid = value; > ret = 1; > out: > - libxl__free_all(&gc); > + GC_FREE; > return ret; > } > > @@ -240,27 +240,27 @@ static int logrename(libxl__gc *gc, const char *old, const char *new) > > int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name) > { > - libxl__gc gc = LIBXL_INIT_GC(ctx); > + GC_INIT(ctx); > struct stat stat_buf; > char *logfile, *logfile_new; > int i, rc; > > - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name); > + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log", name); > if (stat(logfile, &stat_buf) == 0) { > /* file exists, rotate */ > - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.10", name); > + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log.10", name); > unlink(logfile); > for (i = 9; i > 0; i--) { > - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i); > - logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i + 1); > - rc = logrename(&gc, logfile, logfile_new); > + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log.%d", name, i); > + logfile_new = libxl__sprintf(gc, "/var/log/xen/%s.log.%d", name, i + 1); > + rc = logrename(gc, logfile, logfile_new); > if (rc) > goto out; > } > - logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name); > - logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.1", name); > + logfile = libxl__sprintf(gc, "/var/log/xen/%s.log", name); > + logfile_new = libxl__sprintf(gc, "/var/log/xen/%s.log.1", name); > > - rc = logrename(&gc, logfile, logfile_new); > + rc = logrename(gc, logfile, logfile_new); > if (rc) > goto out; > } else { > @@ -272,7 +272,7 @@ int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name) > *full_name = strdup(logfile); > rc = 0; > out: > - libxl__free_all(&gc); > + GC_FREE; > return rc; > } > > -- > 1.7.2.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel
Ian Campbell
2011-Dec-07 16:34 UTC
Re: [PATCH 13/15] libxl: make LIBXL_INIT_GC a statement, not an initialiser
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> Previously LIBXL_INIT_GC was an initialiser, which you were expected > to use like this: > libxl__gc gc = LIBXL_INIT_GC(ctx); > > But we are going to want to put things in the gc which are to be > initialised using other macros. That means that LIBXL_INIT_GC has to > become a statement too. So instead, we make it so that it''s used like this: > libxl_gc gc; > LIBXL_INIT_GC(gc,ctx); > > In fact there is only one caller now, GC_INIT,Maybe we should just fold LIBXL_INIT_GC into GC_INIT then?> which uses this trick: > libxl_gc gc[1]; > LIBXL_INIT_GC(gc[0],ctx);Ian.> > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> > --- > tools/libxl/libxl_internal.h | 9 +++++++-- > 1 files changed, 7 insertions(+), 2 deletions(-) > > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index 1d1dc35..d015c7c 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -145,7 +145,12 @@ typedef struct { > libxl_ctx *owner; > } libxl__gc; > > -#define LIBXL_INIT_GC(ctx) (libxl__gc){ .alloc_maxsize = 0, .alloc_ptrs = 0, .owner = ctx } > +#define LIBXL_INIT_GC(gc,ctx) do{ \ > + (gc).alloc_maxsize = 0; \ > + (gc).alloc_ptrs = 0; \ > + (gc).owner = (ctx); \ > + } while(0) > + > static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) > { > return gc->owner; > @@ -676,7 +681,7 @@ libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); > * as a local variable. > */ > > -#define GC_INIT(ctx) libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) } > +#define GC_INIT(ctx) libxl__gc gc[1]; LIBXL_INIT_GC(gc[0],ctx) > #define GC_FREE libxl__free_all(gc) > #define CTX libxl__gc_owner(gc) >
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote: [...]> Please review. I would like to apply 12/15 in particular ASAP, as it > is textually very intrusive. I think 01-12 ought to be pretty > uncontroversial by now, and I have now tested 02/15 so I think it''s > ready to go in.I think I have now acked #1-11 either previously or just now, although my comment on #12 really is about #7 so having either dismissed or implemented that suggestion I''ve effectively acked #1-12.> 14 and 15 have the meat.I''ll look at these next.> > Ian. > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel
Ian Campbell
2011-Dec-07 17:35 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h > index 289dc85..654a5b0 100644 > --- a/tools/libxl/libxl.h > +++ b/tools/libxl/libxl.h > @@ -137,6 +137,7 @@ > #include <xen/sysctl.h> > > #include <libxl_uuid.h> > +#include <_libxl_list.h>Do we expose the use of these to users anywhere? I''ve failed to spot it if so (at least in this patch). If it is deliberate then #3 needs to install this header.> [...] > @@ -635,6 +639,8 @@ const char *libxl_lock_dir_path(void); > const char *libxl_run_dir_path(void); > const char *libxl_xenpaging_dir_path(void); > > +#include <libxl_event.h> > +Putting this at the end is a bit odd, I don''t really object though. I suppose it depends on stuff defined in this header and putting it half way through is even more odd.> #endif /* LIBXL_H */ > > /* > diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c > new file mode 100644 > index 0000000..8d4dbf6 > --- /dev/null > +++ b/tools/libxl/libxl_event.c > @@ -0,0 +1,711 @@ > +/* > + * Copyright (C) 2011 Citrix Ltd. > + * > + * 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.I''ve only just noticed this but it is present in some other libxl files too. There is no LICENSE file in tools/libxl: $ find -name LICENSE ./tools/ioemu-remote/LICENSE ./tools/ioemu-remote/tcg/LICENSE ./tools/ocaml/LICENSE ./xen/tools/figlet/LICENSE I suspect this is a cut-and-paste-o, probably from tools/ocaml?> + * > + * 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. > + */ > +/* > + * Internal event machinery for use by other parts of libxl > + */ > + > +#include <poll.h> > + > +#include "libxl_internal.h" > + > +/* > + * The counter osevent_in_hook is used to ensure that the application > + * honours the reentrancy restriction documented in libxl_event.h. > + * > + * The application''s registration hooks should be called ONLY via > + * these macros, with the ctx locked. Likewise all the "occurred" > + * entrypoints from the application should assert(!in_hook);In RFC speak you mean MUST rather than should both times here, right?> + */ > +#define OSEVENT_HOOK_INTERN(defval, hookname, ...) \ > + (CTX->osevent_hooks \ > + ? (CTX->osevent_in_hook++, \ > + CTX->osevent_hooks->hookname(CTX->osevent_user, __VA_ARGS__), \ > + CTX->osevent_in_hook--) \ > + : defval) > + > +#define OSEVENT_HOOK(hookname,...) \ > + OSEVENT_HOOK_INTERN(0, hookname, __VA_ARGS__) > + > +#define OSEVENT_HOOK_VOID(hookname,...) \ > + OSEVENT_HOOK_INTERN((void)0, hookname, __VA_ARGS__) > + > +/* > + * fd events > + */ > + > +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, > + libxl__ev_fd_callback *func, > + int fd, short events) {Strictly speaking CODING_STYLE requires the { to be on the next line.> + int rc; > + > + assert(fd >= 0); > + > + CTX_LOCK; > + > + rc = OSEVENT_HOOK(fd_register, fd, &ev->for_app_reg, events, ev); > + if (rc) goto out; > + > + LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry); > + > + ev->fd = fd; > + ev->events = events; > + ev->in_beforepolled = -1; > + ev->func = func;Even though this is all locked correctly seeing the ev initialised after it is already on the list has tweaked my "what''s up" instinct such that I''ve had to look twice both times I''ve looked at this patch.> + > + rc = 0; > + > + out: > + CTX_UNLOCK; > + return rc; > +} > +[...]> +int libxl__ev_time_register_rel(libxl__gc *gc, libxl__ev_time *ev, > + libxl__ev_time_callback *func, > + int milliseconds /* as for poll(2) */) { > + struct timeval abs; > + int rc; > + > + CTX_LOCK; > + > + if (milliseconds < 0) { > + ev->infinite = 1;diff has inconveniently chosen to present me with the implementation before the interface. /me scurries off to read libxl_events.h. OK I see why this == infinite now (it even tells me 5 lines before, oh well).> + } else { > + rc = time_rel_to_abs(gc, milliseconds, &abs); > + if (rc) goto out; > + > + rc = time_register_finite(gc, ev, abs); > + if (rc) goto out; > + } > + > + ev->func = func; > + rc = 0; > + > + out: > + CTX_UNLOCK; > + return 0;You mean "return rc" here.> +} > + > +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev, > + struct timeval abs) { > + int rc; > + > + CTX_LOCK; > + > + assert(libxl__ev_time_isregistered(ev));Why is there no deregister here? Is libxl__ev_time_modify_rel the only caller?> + > + if (ev->infinite) { > + rc = time_register_finite(gc, ev, abs); > + if (rc) goto out; > + } else { > + rc = OSEVENT_HOOK(timeout_modify, &ev->for_app_reg, abs); > + if (rc) goto out; > + > + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); > + ev->abs = abs; > + time_insert_finite(gc, ev); > + } > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return rc; > +} > + > +int libxl__ev_time_modify_rel(libxl__gc *gc, libxl__ev_time *ev, > + int milliseconds) { > + struct timeval abs; > + int rc; > + > + CTX_LOCK; > + > + assert(libxl__ev_time_isregistered(ev)); > + > + if (milliseconds < 0) { > + time_deregister(gc, ev); > + ev->infinite = 1; > + rc = 0; > + goto out; > + } > + > + rc = time_rel_to_abs(gc, milliseconds, &abs); > + if (rc) goto out; > + > + rc = libxl__ev_time_modify_abs(gc, ev, abs); > + if (rc) goto out; > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return 0;> [...] > + > +/* > + * xenstore watches > + */ > +[...] > + > +static void watchfd_callback(libxl__gc *gc, libxl__ev_fd *ev, > + int fd, short events, short revents) { > + for (;;) { > + char **event = xs_check_watch(CTX->xsh); > + if (!event) { > + if (errno == EAGAIN) break; > + if (errno == EINTR) continue; > + LIBXL__EVENT_DISASTER(gc, "cannot check/read watches", errno, 0); > + return; > + } > + > + const char *epath = event[0]; > + const char *token = event[1]; > + int slotnum; > + uint32_t counterval; > + int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval);How have I never come across the SCNxxx counterpart to PRIxxx before!> + if (rc != 2) { > + LIBXL__LOG(CTX, LIBXL__LOG_ERROR, > + "watch epath=%s token=%s: failed to parse token", > + epath, token); > + /* oh well */ > + goto ignore; > + } > + if (slotnum < 0 || slotnum >= CTX->watch_nslots) { > + /* perhaps in the future we will make the watchslots array shrink */ > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, "watch epath=%s token=%s:" > + " slotnum %d out of range [0,%d>", > + epath, token, slotnum, CTX->watch_nslots); > + goto ignore; > + } > + > + libxl__ev_xswatch *w = libxl__watch_slot_contents(gc, slotnum); > + > + if (!w) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: empty slot", > + epath, token); > + goto ignore; > + } > + > + if (w->counterval != counterval) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: counter != %"PRIx32, > + epath, token, w->counterval); > + goto ignore; > + } > + > + /* Now it''s possible, though unlikely, that this was an event > + * from a previous use of the same slot with the same counterval. > + * > + * In that case either: > + * - the event path is a child of the watch path, in > + * which case this watch would really have generated this > + * event if it had been registered soon enough and we are > + * OK to give this possibly-spurious event to the caller; or > + * - it is not, in which case we must suppress it as the > + * caller should not see events for unrelated paths. > + * > + * See also docs/misc/xenstore.txt. > + */ > + size_t epathlen = strlen(epath); > + size_t wpathlen = strlen(w->path); > + if (epathlen < wpathlen || > + memcmp(epath, w->path, wpathlen) || > + (epathlen > wpathlen && epath[wpathlen] != ''/'')) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: not child of wpath=%s", > + epath, token, w->path);It seems like this is worthy of a helper function of its own. Possibly in libxenstore itself?> + goto ignore; > + } > + > + /* At last, we have checked everything! */Huzzah!> + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch event: epath=%s token=%s wpath=%s w=%p", > + epath, token, w->path, w);Aside: At some point we might want to have a way to configure classes of debug log message on/off. I was just wondering if this message might be a bit spammy but I suspect it is ok.> + w->callback(gc, w, w->path, epath); > + > + ignore: > + free(event); > + } > +}[...]> +int libxl__ev_xswatch_register(libxl__gc *gc, libxl__ev_xswatch *w, > + libxl__ev_xswatch_callback *func, > + const char *path /* copied */) { > + libxl__ev_watch_slot *use = NULL; > + char *path_copy = NULL; > + int rc; > + > + CTX_LOCK; > + > + if (!libxl__ev_fd_isregistered(&CTX->watch_efd)) { > + rc = libxl__ev_fd_register(gc, &CTX->watch_efd, watchfd_callback, > + xs_fileno(CTX->xsh), POLLIN); > + if (rc) goto out_rc; > + } > + > + if (LIBXL_SLIST_EMPTY(&CTX->watch_freeslots)) { > + /* Free list is empty so there is not in fact a linked > + * free list in the array and we can safely realloc it */ > + int newarraysize = (CTX->watch_nslots + 1) << 2; > + int i; > + libxl__ev_watch_slot *newarray > + realloc(CTX->watch_slots, sizeof(*newarray) * newarraysize); > + if (!newarray) goto out_nomem; > + for (i=CTX->watch_nslots; i<newarraysize; i++) > + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, > + &newarray[i], empty); > + CTX->watch_slots = newarray; > + CTX->watch_nslots = newarraysize; > + } > + use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots); > + assert(use); > + LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty);I presume this is removing "use" from the list. It seems odd to refer to that element of the list as HEAD and FIRST interchangeably since it doesn''t make this obvious but I guess we got this API from elsewhere. There''s no get-and-return function which combines the two operations?> + > + path_copy = strdup(path); > + if (!path_copy) goto out_nomem; > + > + int slotnum = use - CTX->watch_slots; > + w->counterval = CTX->watch_counter++; > + > + if (!xs_watch(CTX->xsh, path, watch_token(gc, slotnum, w->counterval))) { > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, > + "create watch for path %s", path); > + rc = ERROR_FAIL; > + goto out_rc; > + } > + > + w->slotnum = slotnum; > + w->path = path_copy; > + w->callback = func; > + /* we look a bit behind the curtain of LIBXL_SLIST, to explictlyexplicitly> + * assign to the pointer that''s the next link. See the comment > + * by the definitionn of libxl__ev_watch_slot */definition. I think this behind the curtain stuff would be better encapsulated in a macro up somewhere near the comment and libxl__ev_watch_slot.> + use->empty.sle_next = (void*)w;> + > + CTX_UNLOCK; > + return 0; > + > + out_nomem: > + rc = ERROR_NOMEM; > + out_rc: > + if (use) > + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, use, empty); > + if (path_copy) > + free(path_copy); > + CTX_UNLOCK; > + return rc; > +} > + > +void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch *w) { > + /* it is legal to deregister from within _callback */and CTX_LOCK is recursive so this is ok.> + CTX_LOCK; > + > + if (w->slotnum >= 0) { > + char *token = watch_token(gc, w->slotnum, w->counterval); > + if (!xs_unwatch(CTX->xsh, w->path, token)) > + /* Oh well, we will just get watch events forever more > + * and ignore them. But we should complain to the log. */ > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, > + "remove watch for path %s", w->path);Is it possible to also unwatch an unexpected watch at the point it fires, IOW to try again later? I havn''et looked at the potential failure cases of xs_unwatch so perhaps once it has failed there is no point in trying again.> + > + libxl__ev_watch_slot *slot = &CTX->watch_slots[w->slotnum]; > + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, slot, empty); > + } > + > + free(w->path); > + w->path = NULL; > + > + CTX_UNLOCK; > +} > + > +/* > + * osevent poll > + */This seems like a good place to stop for the day. I''ll pickup the rest tomorrow. [...]
Ian Campbell
2011-Dec-08 09:47 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
> [...snip already reviewed bits...] > +/* > + * osevent poll > + */ > + > +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > + struct pollfd *fds, int *timeout_upd, > + struct timeval now) { > + libxl__ev_fd *efd; > + int i; > + > + /* > + * In order to be able to efficiently find the libxl__ev_fd > + * for a struct poll during _afterpoll, we maintain a shadow > + * data structure in CTX->fd_beforepolled: each slot in > + * the fds array corresponds to a slot in fd_beforepolled. > + */ > + > + GC_INIT(ctx); > + CTX_LOCK; > + > + if (*nfds_io) { > + /* > + * As an optimisation, we don''t touch fd_beforepolled_used > + * if *nfds_io is zero on entry, since in that case the > + * caller just wanted to know how big an array to give us. > + * > + * If !*nfds_io, the unconditional parts below are guaranteed > + * not to mess with fd_beforepolled... or any in_beforepolled. > + */ > + > + /* Remove all the old references into beforepolled */ > + for (i = 0; i < CTX->fd_beforepolled_used; i++) { > + efd = CTX->fd_beforepolled[i]; > + if (efd) { > + assert(efd->in_beforepolled == i); > + efd->in_beforepolled = -1; > + CTX->fd_beforepolled[i] = NULL; > + } > + } > + CTX->fd_beforepolled_used = 0; > + > + /* make sure our array is as big as *nfds_io */ > + if (CTX->fd_beforepolled_allocd < *nfds_io) { > + assert(*nfds_io < INT_MAX / sizeof(libxl__ev_fd*) / 2);What is the /2 for?> + libxl__ev_fd **newarray > + realloc(CTX->fd_beforepolled, sizeof(*newarray) * *nfds_io); > + if (!newarray) > + return ERROR_NOMEM;Need to CTX_UNLOCK here.> + CTX->fd_beforepolled = newarray; > + CTX->fd_beforepolled_allocd = *nfds_io; > + } > + } > + > + int used = 0; > + LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) { > + if (used < *nfds_io) { > + fds[used].fd = efd->fd; > + fds[used].events = efd->events; > + fds[used].revents = 0; > + CTX->fd_beforepolled[used] = efd; > + efd->in_beforepolled = used; > + } > + used++; > + } > + int rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL; > + > + if (*nfds_io) { > + CTX->fd_beforepolled_used = used; > + } > + > + *nfds_io = used; > + > + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); > + if (etime) { > + int our_timeout; > + struct timeval rel; > + static struct timeval zero; > + > + timersub(&etime->abs, &now, &rel); > + > + if (timercmp(&rel, &zero, <)) { > + our_timeout = 0; > + } else if (rel.tv_sec >= 2000000) { > + our_timeout = 2000000000; > + } else { > + our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000; > + } > + if (*timeout_upd < 0 || our_timeout < *timeout_upd) > + *timeout_upd = our_timeout; > + } > + > + CTX_UNLOCK; > + GC_FREE; > + return rc; > +} > + > +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, > + struct timeval now) { > + int i; > + GC_INIT(ctx); > + CTX_LOCK; > + > + assert(nfds <= CTX->fd_beforepolled_used); > + > + for (i = 0; i < nfds; i++) { > + if (!fds[i].revents) > + continue; > + > + libxl__ev_fd *efd = CTX->fd_beforepolled[i]; > + if (!efd) > + continue;Would this be a bug? If we''ve set it up for polling how can it be NULL?> + > + assert(efd->in_beforepolled == i); > + assert(fds[i].fd == efd->fd); > + > + int revents = fds[i].revents & efd->events; > + if (!revents) > + continue; > + > + efd->func(gc, efd, efd->fd, efd->events, revents); > + } > + > + for (;;) { > + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); > + if (!etime) > + break; > + > + assert(!etime->infinite); > + > + if (timercmp(&etime->abs, &now, >)) > + break; > + > + time_deregister(gc, etime); > + > + etime->func(gc, etime, &etime->abs); > + } > + > + CTX_UNLOCK; > + GC_FREE; > +} > + > + > +/* > + * osevent hook and callback machinery > + */ > + > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > + const libxl_osevent_hooks *hooks, > + void *user) { > + GC_INIT(ctx);I nearly said, "there''s no gc used in this function" but actually it is artfully concealed in CTX_LOCK. I wonder if CTX_LOCK should take the context, e.g. either CTX_LOCK(CTX) or CTX_LOCK(ctx)? Another alternative would be to have CTX_INIT to parallel GC_INIT which creates a local *ctx instead of having CTX. This would also avoid the need to s/CTX/ctx/ if you make an internal function into an external one and vice versa.> + CTX_LOCK; > + ctx->osevent_hooks = hooks; > + ctx->osevent_user = user; > + CTX_UNLOCK; > + GC_FREE; > +} > + > +[...]> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h > new file mode 100644 > index 0000000..25efbdf > --- /dev/null > +++ b/tools/libxl/libxl_event.h > @@ -0,0 +1,199 @@[...]> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > + struct pollfd *fds, int *timeout_upd, > + struct timeval now); > + /* The caller should provide beforepoll with some space for libxl''s > + * fds, and tell libxl how much space is available by setting *nfds_io. > + * fds points to the start of this space (and fds may be a pointer into > + * a larger array, for example, if the application has some fds of > + * its own that it is interested in). > + * > + * On return *nfds_io will in any case have been updated by libxl > + * according to how many fds libxl wants to poll on. > + * > + * If the space was sufficient, libxl fills in fds[0..<new > + * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed, > + * and returns ok. > + * > + * If space was insufficient, fds[0..<old *nfds_io>] is undefined on > + * return; *nfds_io on return will be greater than the value on > + * entry; *timeout_upd may or may not have been updated; and > + * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this caseERROR_BUFFERFULL [...]> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index d015c7c..88e7dbb 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h[...]> @@ -138,12 +218,12 @@ typedef struct { > > #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y))) > > -typedef struct { > +struct libxl__gc { > /* mini-GC */ > int alloc_maxsize; > void **alloc_ptrs; > libxl_ctx *owner; > -} libxl__gc; > +};Is this an unrelated change which has snuck in? I''d hack expected an equivalent change to GC_INIT if not. [...]> -- > 1.7.2.5Phew!
On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:> Replace the existing API for retrieving high-level events (events > about domains, etc.) from libxl with a new one. > > This changes the definition and semantics of the `libxl_event'' > structure, and replaces the calls for obtaining information about > domain death and disk eject events. > > This is an incompatible change, sorry. The alternative was to try to > provide both the previous horrid API and the new one, and would also > involve never using the name `libxl_event'' for the new interface. > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> > --- > tools/libxl/libxl.c | 302 ++++++++++++++++++++++++++++++------------ > tools/libxl/libxl.h | 55 ++------- > tools/libxl/libxl_event.c | 188 ++++++++++++++++++++++++--- > tools/libxl/libxl_event.h | 180 ++++++++++++++++++++++++- > tools/libxl/libxl_internal.c | 6 + > tools/libxl/libxl_internal.h | 81 +++++++++++- > tools/libxl/libxl_types.idl | 35 ++++- > tools/libxl/xl_cmdimpl.c | 270 ++++++++++++++++++++++---------------- > 8 files changed, 839 insertions(+), 278 deletions(-) > > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index 58f280c..ba9293b 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -614,117 +631,173 @@ int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req) > return 0; > } > > -int libxl_get_wait_fd(libxl_ctx *ctx, int *fd) > -{ > - *fd = xs_fileno(ctx->xsh); > - return 0; > -} > +static void domain_death_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch *w, > + const char *wpath, const char *epath) { > + libxl_evgen_domain_death *evg; > + uint32_t domid; > + int rc;Ugh, diff has made some very unhelpful choices about how to display this change. Oh well. I''ve snipped all the - bits to try and make it easier to follow. [...]> + CTX_LOCK;[...]> + uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid); > + evg = LIBXL_TAILQ_FIRST(&CTX->death_list); > + if (!evg) goto out; > > + domid = evg->domid; >[...]> + for (;;) { > + int nentries = LIBXL_TAILQ_NEXT(evg, entry) ? 200 : 1; > + xc_domaininfo_t domaininfos[nentries]; > + const xc_domaininfo_t *got = domaininfos, *gotend; > + > + rc = xc_domain_getinfolist(CTX->xch, domid, nentries, domaininfos); > + if (rc == -1) { > + LIBXL__EVENT_DISASTER(gc, "xc_domain_getinfolist failed while" > + " processing @releaseDomain watch event", > + errno, 0); > goto out;[...]> + } > + gotend = &domaininfos[rc]; > + > + for (;;) { > + if (!evg) > + goto all_reported; > + > + if (!rc || got->domain > evg->domid) { > + /* ie, the list doesn''t contain evg->domid any more so > + * the domain has been destroyed */ > + libxl_evgen_domain_death *evg_next; > + > + libxl_event *ev = NEW_EVENT(gc, DOMAIN_DESTROY, evg->domid); > + if (!ev) goto out; > + > + libxl__event_occurred(gc, ev); > + > + evg->death_reported = 1; > + evg_next = LIBXL_TAILQ_NEXT(evg, entry); > + LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry); > + LIBXL_TAILQ_INSERT_HEAD(&CTX->death_reported, evg, entry); > + evg = evg_next; > + > + continue; > + } > + > + if (got == gotend) > + break; > + > + if (got->domain < evg->domid) { > + got++; > + continue; > + } > + > + assert(evg->domid == got->domain); > + > + if (!evg->shutdown_reported && > + (got->flags & XEN_DOMINF_shutdown)) { > + libxl_event *ev = NEW_EVENT(gc, DOMAIN_SHUTDOWN, got->domain); > + if (!ev) goto out; > + > + ev->u.domain_shutdown.shutdown_reason > + (got->flags >> XEN_DOMINF_shutdownshift) & > + XEN_DOMINF_shutdownmask; > + libxl__event_occurred(gc, ev); > + > + evg->shutdown_reported = 1; > + } > + evg = LIBXL_TAILQ_NEXT(evg, entry); > + } > + > + assert(rc); /* rc==0 results in us eating all evgs and quitting */ > + domid = gotend[-1].domain; > }[...]> + all_reported: > + out: > + > + CTX_UNLOCK; > } >[...]> +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid, > + libxl_ev_user user, libxl_evgen_domain_death **evgen_out) { > + GC_INIT(ctx); > + libxl_evgen_domain_death *evg, *evg_search; > + int rc; > + > + CTX_LOCK; > + > + evg = malloc(sizeof(*evg)); if (!evg) { rc = ERROR_NOMEM; goto out; }CODING_STYLE?> + memset(evg, 0, sizeof(*evg)); > + evg->domid = domid; > + evg->user = user; > + > + LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, , > + evg->domid > evg_search->domid); > + > + if (!libxl__ev_xswatch_isregistered(&ctx->death_watch)) { > + rc = libxl__ev_xswatch_register(gc, &ctx->death_watch, > + domain_death_xswatch_callback, "@releaseDomain"); > + if (rc) { libxl__evdisable_domain_death(gc, evg); goto out; } > }[...]> + rc = 0; >[...]> + out: > + CTX_UNLOCK; > + return rc; > +}; >[...]> +void libxl__evdisable_domain_death(libxl__gc *gc, > + libxl_evgen_domain_death *evg) { > + CTX_LOCK; >[...]> + if (!evg->death_reported) > + LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry); > + else > + LIBXL_TAILQ_REMOVE(&CTX->death_reported, evg, entry); >[...]> + free(evg); > + > + if (!LIBXL_TAILQ_FIRST(&CTX->death_list) && > + libxl__ev_xswatch_isregistered(&CTX->death_watch)) > + libxl__ev_xswatch_deregister(gc, &CTX->death_watch); >[...]> + CTX_UNLOCK; > } >[...]> +void libxl_evdisable_domain_death(libxl_ctx *ctx, > + libxl_evgen_domain_death *evg) { > GC_INIT(ctx);[...]> + libxl__evdisable_domain_death(gc, evg); > + GC_FREE; > +} > + > +static void disk_eject_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch *watch, > + const char *wpath, const char *epath) { > + libxl_evgen_disk_eject *evg = (void*)watch; > char *backend; > char *value; > char backend_type[BACKEND_STRING_SIZE+1]; >[...]> + value = libxl__xs_read(gc, XBT_NULL, wpath); >[...]> + if (!value || strcmp(value, "eject")) > + return; > + > + if (libxl__xs_write(gc, XBT_NULL, wpath, "")) { > + LIBXL__EVENT_DISASTER(gc, "xs_write failed acknowledging eject", > + errno, LIBXL_EVENT_TYPE_DISK_EJECT); > + return; > } > > - path = strdup(event->path);[...]> + libxl_event *ev = NEW_EVENT(gc, DISK_EJECT, evg->domid); > + libxl_device_disk *disk = &ev->u.disk_eject.disk; > + > + backend = libxl__xs_read(gc, XBT_NULL, > + libxl__sprintf(gc, "%.*s/backend", > + (int)strlen(wpath)-6, wpath));This pattern crops up a lot in libxl. I keep wondering if libxl__xs_read shouldn''t take a fmt string and varargs. Not sure how you would do that in a way which allowed libxl__xs_write to have an orthogonal (and still sane) interface though.> > sscanf(backend,[...]> + "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE) > + "[a-z]/%*d/%*d", > + &disk->backend_domid, backend_type); > if (!strcmp(backend_type, "tap") || !strcmp(backend_type, "vbd")) { > disk->backend = LIBXL_DISK_BACKEND_TAP; > } else if (!strcmp(backend_type, "qdisk")) { > @@ -733,19 +806,72 @@ int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event > disk->backend = LIBXL_DISK_BACKEND_UNKNOWN; > } >[...]> + disk->pdev_path = strdup(""); /* xxx fixme malloc failure */ > disk->format = LIBXL_DISK_FORMAT_EMPTY; > /* this value is returned to the user: do not free right away */[...]> + disk->vdev = xs_read(CTX->xsh, XBT_NULL, > + libxl__sprintf(gc, "%s/dev", backend), NULL); > disk->removable = 1; > disk->readwrite = 0; > disk->is_cdrom = 1; >[...]> + libxl__event_occurred(gc, ev); > +} > +[...]> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h > index 654a5b0..17b15a6 100644 > --- a/tools/libxl/libxl.h > +++ b/tools/libxl/libxl.h > @@ -53,7 +53,10 @@ > * A public function may be called from within libxl; the call > * context initialisation macros will make sure that the internal > * caller''s context is reused (eg, so that the same xenstore > - * transaction is used). > + * transaction is used). But in-libxl callers of libxl public > + * functions should note that any libxl public function may cause > + * recursively reentry into libxl via the application''s event > + * callback hook. > * > * Public functions have names like libxl_foobar. > * > @@ -152,6 +155,8 @@ void libxl_key_value_list_dispose(libxl_key_value_list *kvl); > > typedef uint32_t libxl_hwcap[8]; > > +typedef uint64_t libxl_ev_user; > + > typedef struct { > uint32_t size; /* number of bytes in map */ > uint8_t *map; > @@ -200,6 +205,9 @@ typedef struct { > int v; > } libxl_enum_string_table; > > +struct libxl_event; > +typedef LIBXL_TAILQ_ENTRY(struct libxl_event) libxl_ev_link;I think I made a comment on an earlier patch about why the list stuff was exposed to the user. I guess I now have my answer. [...]> diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c > index 8d4dbf6..ec5c25e 100644 > --- a/tools/libxl/libxl_event.c > +++ b/tools/libxl/libxl_event.c[...]> @@ -703,6 +713,152 @@ void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval, > } > > /* > + * Event retrieval etc. > + */ > + > +void libxl_event_register_callbacks(libxl_ctx *ctx, > + const libxl_event_hooks *hooks, void *user) { > + ctx->event_hooks = hooks; > + ctx->event_hooks_user = user;Does this either need locking or a check that there are no events in flight? Or is it invalid to change hooks once they are registered?> +} > + > +void libxl__event_occurred(libxl__gc *gc, libxl_event *event) { > + if (CTX->event_hooks && > + (CTX->event_hooks->event_occurs_mask & (1UL << event->type))) { > + /* libxl__free_all will call the callback, just before exit > + * from libxl. This helps avoid reentrancy bugs: parts of > + * libxl that call libxl__event_occurred do not have to worry > + * that libxl might be reentered at that point. */ > + LIBXL_TAILQ_INSERT_TAIL(&gc->occurred_for_callback, event, link); > + return;This return seem surplus to requirements.> + } else { > + LIBXL_TAILQ_INSERT_TAIL(&CTX->occurred, event, link); > + } > +} > + > +void libxl_event_free(libxl_ctx *ctx, libxl_event *event) { > + libxl_event_dispose(event); > + free(event); > +} > + > +libxl_event *libxl__event_new(libxl__gc *gc, > + libxl_event_type type, uint32_t domid) { > + libxl_event *ev; > + > + ev = malloc(sizeof(*ev)); > + if (!ev) { > + LIBXL__EVENT_DISASTER(gc, "allocate new event", errno, type); > + return NULL; > + } > + > + memset(ev, 0, sizeof(*ev)); > + ev->type = type; > + ev->domid = domid; > + > + return ev; > +} > + > +static int event_check_unlocked(libxl__gc *gc, libxl_event **event_r,The *_unlocked functions are slightly confusing, since what it really means is "caller must have taken the lock already" rather than "you can call this unlocked". I''m not sure what would be better though.> + unsigned long typemask, > + libxl_event_predicate *pred, void *pred_user) { > + libxl_event *ev; > + int rc; > + > + LIBXL_TAILQ_FOREACH(ev, &CTX->occurred, link) { > + if (!(typemask & (1UL << ev->type))) > + continue; > + > + if (pred && !pred(ev, pred_user)) > + continue; > + > + /* got one! */ > + LIBXL_TAILQ_REMOVE(&CTX->occurred, ev, link); > + *event_r = ev; > + rc = 0; > + goto out; > + } > + rc = ERROR_NOT_READY; > + > + out: > + return rc; > +} > + > +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, > + unsigned long typemask, > + libxl_event_predicate *pred, void *pred_user) { > + GC_INIT(ctx); > + CTX_LOCK; > + int rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); > + CTX_UNLOCK; > + GC_FREE; > + return rc; > +} > + > +int libxl_event_wait(libxl_ctx *ctx, libxl_event **event_r, > + unsigned long typemask, > + libxl_event_predicate *pred, void *pred_user) { > + int rc; > + struct timeval now; > + > + GC_INIT(ctx); > + CTX_LOCK; > + > + for (;;) { > + rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); > + if (rc != ERROR_NOT_READY) goto out; > + > + rc = libxl__gettimeofday(gc, &now); > + if (rc) goto out; > + > + int timeout; > + > + for (;;) { > + int nfds = CTX->fd_polls_allocd; > + timeout = -1; > + rc = beforepoll_unlocked(gc, &nfds, CTX->fd_polls, &timeout, now); > + if (!rc) break; > + if (rc != ERROR_BUFFERFULL) goto out; > + > + struct pollfd *newarray > + (nfds > INT_MAX / sizeof(struct pollfd) / 2) ? 0 :I think I''ve seen this construct before. I think it''s worth a #define. Hrm, was the other one a different struct in the sizeof? *scrobbles around*. Yes, it was libxl__ev_fd* in that case and we were setting up the before polled array. However aren''t these two arrays related (one is a shadow of the other)? IOW isn''t the real limit the minimum of the two cases?> + realloc(CTX->fd_polls, sizeof(*newarray) * nfds); > + > + if (!newarray) { rc = ERROR_NOMEM; goto out; } > + > + CTX->fd_polls = newarray; > + CTX->fd_polls_allocd = nfds; > + } > + > + rc = poll(CTX->fd_polls, CTX->fd_polls_allocd, timeout); > + if (rc < 0) { > + if (errno == EINTR) continue; > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, "poll failed"); > + rc = ERROR_FAIL; > + goto out; > + } > + > + rc = libxl__gettimeofday(gc, &now); > + if (rc) goto out; > + > + afterpoll_unlocked(gc, CTX->fd_polls_allocd, CTX->fd_polls, now); > + > + /* we unlock and free the gc each time we go through this loop, > + * so that (a) we don''t accumulate garbage and (b) any events > + * which are to be dispatched by callback are actually delivered > + * in a timely fashion. > + */ > + CTX_UNLOCK; > + libxl__free_all(gc); > + CTX_LOCK; > + } > + > + out: > + CTX_UNLOCK; > + GC_FREE; > + return rc; > +} > + > +/* > * Local variables: > * mode: C > * c-basic-offset: 4 > diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h > index 25efbdf..bbe1ed0 100644 > --- a/tools/libxl/libxl_event.h > +++ b/tools/libxl/libxl_event.h[...]> +/* Alternatively or additionally, the application may also use this: */ > + > +typedef struct libxl_event_hooks { > + uint64_t event_occurs_mask; > + void (*event_occurs)(void *user, const libxl_event *event); > + void (*disaster)(void *user, libxl_event_type type, > + const char *msg, int errnoval); > +} libxl_event_hooks; > + > +void libxl_event_register_callbacks(libxl_ctx *ctx, > + const libxl_event_hooks *hooks, void *user); > + /* > + * Arranges that libxl will henceforth call event_occurs for any > + * events whose type is set in event_occurs_mask, rather than > + * queueing the event for retrieval by libxl_event_check/wait. > + * Events whose bit is clear in mask are not affected.Earlier on you said that applications can mix and match the style of event retrieval they use. Is it the case that for any given event type it will be delivered by exactly of the two mechanisms? IOW if an event type is in event_occurs_mask it will never be delivered via libxl_event_check/wait and vice versa?> + * > + * event becomes owned by the application and must be freed, either > + * by event_occurs or later. > + *[...]> + * Applications should ensure that they eventually retrieve every > + * event using libxl_event_check or libxl_event_wait, since events > + * which occur but are not retreived by the application will be queuedretrieved> + * inside libxl indefinitely.Which is inevitably going to lead to disaster being called... This only applies to every enabled event which is not delivered via the callback mechanism, correct?> libxl_event_check/_wait may be O(n) > + * where n is the number of queued events which do not match the > + * criteria specified in the arguments to check/wait. > + */ > + > +typedef struct libxl__evgen_domain_death libxl_evgen_domain_death; > +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid, > + libxl_ev_user, libxl_evgen_domain_death **evgen_out); > +void libxl_evdisable_domain_death(libxl_ctx *ctx, libxl_evgen_domain_death*); > + /* Arranges for the generation of DOMAIN_SHUTDOWN and DOMAIN_DESTROY > + * events. A domain which is destroyed before it shuts down > + * may generate only a DESTROY event. > + */ > + > +typedef struct libxl__evgen_disk_eject libxl_evgen_disk_eject; > +int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t domid, const char *vdev, > + libxl_ev_user, libxl_evgen_disk_eject **evgen_out); > +void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject*); > + /* Arranges for the generation of DISK_EJECT events. A copy of the > + * string *vdev will be made for libxl''s internal use, and a pointer > + * to this (or some other) copy will be returned as the vdev > + * member of event.u.Should event.u.vdev therefore be const? (skipping forward to the IDL addition it seems not to be)> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index 88e7dbb..518a06d 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -154,11 +154,44 @@ typedef struct libxl__ev_watch_slot { > > libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum); > > + > +/* > + * evgen structures, which are the state we use for generating > + * events for the caller. > + * > + * In general in each case there''s an internal and an external > + * version of the _evdisable_FOO function; the internal one is > + * used during cleanup. > + */ > + > +struct libxl__evgen_domain_death { > + uint32_t domid; > + unsigned shutdown_reported:1, death_reported:1; > + LIBXL_TAILQ_ENTRY(libxl_evgen_domain_death) entry; > + /* on list .death_reported ? CTX->death_list : CTX->death_reported */Isn''t this the other way round?> + libxl_ev_user user; > +}; > +_hidden void > +libxl__evdisable_domain_death(libxl__gc*, libxl_evgen_domain_death*); > +[...]> @@ -250,7 +295,9 @@ static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) > */ > /* register @ptr in @gc for free on exit from outermost libxl callframe. */ > _hidden int libxl__ptr_add(libxl__gc *gc, void *ptr); > -/* if this is the outermost libxl callframe then free all pointers in @gc */ > +/* if this is the outermost libxl callframe then free all pointers in @gc > + * and report all occurred events via callback, if applicable. > + * May reenters the application so must not be called with ctx locked. */reenter> _hidden void libxl__free_all(libxl__gc *gc); > /* allocate and zero @bytes. (similar to a gc''d malloc(3)+memzero()) */ > _hidden void *libxl__zalloc(libxl__gc *gc, int bytes);[...]> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl > index d59d2cb..5a713f0 100644 > --- a/tools/libxl/libxl_types.idl > +++ b/tools/libxl/libxl_types.idl > @@ -75,11 +75,6 @@ libxl_action_on_shutdown = Enumeration("action_on_shutdown", [ > (6, "COREDUMP_RESTART"), > ]) > > -libxl_event_type = Enumeration("event_type", [ > - (1, "DOMAIN_DEATH"), > - (2, "DISK_EJECT"), > - ]) > - > libxl_button = Enumeration("button", [ > (1, "POWER"), > (2, "SLEEP"), > @@ -381,3 +376,33 @@ libxl_sched_credit = Struct("sched_credit", [ > ("weight", integer), > ("cap", integer), > ], dispose_fn=None) > + > +libxl_event_type = Enumeration("event_type", [ > + (1, "DOMAIN_SHUTDOWN"), > + (2, "DOMAIN_DESTROY"), > + (3, "DISK_EJECT"), > + ]) > + > +libxl_ev_user = Number("libxl_ev_user") > + > +libxl_ev_link = Builtin("ev_link", passby=PASS_BY_REFERENCE, private=True) > + > +libxl_event = Struct("event",[ > + ("link", libxl_ev_link,0,The third member here is supposed to be a bool hence "False". I guess python lets you get away with that. (this aspect of the IDL sucks, it should allow for named parameters instead of an opaque, variably size, tuple)> + "for use by libxl; caller may use this once the event has been" > + " returned by libxl_event_{check,wait}"), > + ("domid", libxl_domid), > + ("domuuid", libxl_uuid), > + ("for_user", libxl_ev_user), > + ("type", libxl_event_type), > + ("u", KeyedUnion(None, libxl_event_type, "type", > + [("domain_shutdown", Struct(None, [ > + ("shutdown_reason", uint8), > + ])), > + ("domain_destroy", Struct(None, [])), > + ("disk_eject", Struct(None, [ > + ("vdev", string), > + ("disk", libxl_device_disk), > + ])), > + ]))]) > + > diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c > index f1e729c..e5738b7 100644 > --- a/tools/libxl/xl_cmdimpl.c > +++ b/tools/libxl/xl_cmdimpl.c[...]> @@ -1439,10 +1465,11 @@ static int create_domain(struct domain_create *dom_info) > const char *restore_file = dom_info->restore_file; > int migrate_fd = dom_info->migrate_fd; > > - int fd, i; > + int i; > int need_daemon = daemonize; > int ret, rc; > - libxl_waiter *w1 = NULL, *w2 = NULL; > + libxl_evgen_domain_death *deathw = NULL; > + libxl_evgen_disk_eject **diskws = NULL; /* one per disk */ > void *config_data = 0; > int config_len = 0; > int restore_fd = -1; > @@ -1647,14 +1674,14 @@ start: > if (errno != EINTR) { > perror("failed to wait for daemonizing child"); > ret = ERROR_FAIL; > - goto error_out; > + goto out; > } > } > if (status) { > libxl_report_child_exitstatus(ctx, XTL_ERROR, > "daemonizing child", child1, status); > ret = ERROR_FAIL; > - goto error_out; > + goto out; > } > ret = domid; > goto out; > @@ -1691,92 +1718,106 @@ start: > } > LOG("Waiting for domain %s (domid %d) to die [pid %ld]", > d_config.c_info.name, domid, (long)getpid());[...]> + ret = libxl_evenable_domain_death(ctx, domid, 0, &deathw); > + if (ret) goto out; >[...]> + if (!diskws) { > + diskws = xmalloc(sizeof(*diskws) * d_config.num_disks); > + for (i = 0; i < d_config.num_disks; i++) > + diskws[i] = NULL; > + } > + for (i = 0; i < d_config.num_disks; i++) { > + ret = libxl_evenable_disk_eject(ctx, domid, d_config.disks[i].vdev, > + 0, &diskws[i]); > + if (ret) goto out; > + }Are all disks ejectable? I think only emulated CDROM devices are and emulated disks and all PV devices are not. Should libxl provide a predicate? Of course it is harmless to wait for an eject on a device which can''t...> + while (1) { > + libxl_event *event; > + ret = domain_wait_event(&event); > + if (ret) goto out; > + > + switch (event->type) { > + > + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: > + LOG("Domain %d has shut down, reason code %d 0x%x", domid, > + event->u.domain_shutdown.shutdown_reason, > + event->u.domain_shutdown.shutdown_reason); > + switch (handle_domain_death(ctx, domid, event, &d_config)) { > + case 2: > + if (!preserve_domain(ctx, domid, event, &d_config)) { > + /* If we fail then exit leaving the old domain in place. */ > + ret = -1; > + goto out; > } >[...]> + /* Otherwise fall through and restart. */ > + case 1: > + libxl_event_free(ctx, event); > + libxl_evdisable_domain_death(ctx, deathw); > + deathw = NULL; > + for (i = 0; i < d_config.num_disks; i++) { > + libxl_evdisable_disk_eject(ctx, diskws[i]); > + diskws[i] = NULL; > }[...]> + /* discard any other events which may have been generated */ > + while (!(ret = libxl_event_check(ctx, &event, > + LIBXL_EVENTMASK_ALL, 0,0))) { > + libxl_event_free(ctx, event); > }[...]> + if (ret != ERROR_NOT_READY) { > + LOG("warning, libxl_event_check (cleanup) failed (rc=%d)", > + ret); > + }This sees likely to be a commonly wanted pattern. Perhaps libxl could provide a helper (or several) to disable all events and drain the queue? [...]> + /* > + * XXX FIXME: If this sleep is not there then domain > + * re-creation fails sometimes. > + */ > + LOG("Done. Rebooting now"); > + sleep(2);The optimistic part of me wonders if this is still the case...> + goto start; > + > + case 0: > + LOG("Done. Exiting now"); > + ret = 0; > + goto out; > + > + default: > + abort(); > + } > + > + case LIBXL_EVENT_TYPE_DOMAIN_DESTROY: > + LOG("Domain %d has been destroyed.", domid); > + ret = 0; > + goto out; > + > + case LIBXL_EVENT_TYPE_DISK_EJECT: > + /* XXX what is this for? */ > + libxl_cdrom_insert(ctx, domid, &event->u.disk_eject.disk);Assuming &event->u.disk_eject.disk is an empty variant of the ejected disk (like libxl_event_get_disk_eject_info used to return) then I think this is "inserting" and empty device, i.e. ejecting it. It might be more obvious to have libxl_cdrom_eject which takes the "full" version of the disk and does the obvious thing (modifying the disk to be empty)?> + break; > + > + default:; > + char *evstr = libxl_event_to_json(ctx, event); > + LOG("warning, got unexpected event type %d, event=%s", > + event->type, evstr); > + free(evstr); > }[...]> + > + libxl_event_free(ctx, event); > } > > error_out: > @@ -2259,43 +2300,46 @@ static void destroy_domain(const char *p) > static void shutdown_domain(const char *p, int wait) > { > int rc; > + libxl_event *event; > > find_domain(p); > rc=libxl_domain_shutdown(ctx, domid, 0); > if (rc) { fprintf(stderr,"shutdown failed (rc=%d)\n",rc);exit(-1); } > > if (wait) {[...]> + libxl_evgen_domain_death *deathw; >[...]> + rc = libxl_evenable_domain_death(ctx, domid, 0, &deathw); > + if (rc) { > + fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc); > + exit(-1); > + } >[...]> + for (;;) { > + rc = domain_wait_event(&event); > + if (rc) exit(-1); >[...]> + switch (event->type) { >[...]> + case LIBXL_EVENT_TYPE_DOMAIN_DESTROY: > + LOG("Domain %d has been destroyed", domid); > + goto done; >[...]> + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: > + LOG("Domain %d has been shut down, reason code %d %x", domid, > + event->u.domain_shutdown.shutdown_reason, > + event->u.domain_shutdown.shutdown_reason); > + goto done; >[...]> + default: > + LOG("Unexpected event type %d", event->type); > + break; > }[...]> + libxl_event_free(ctx, event); > }[...]> + done: > + libxl_event_free(ctx, event); > + libxl_evdisable_domain_death(ctx, deathw); > } > } > > -- > 1.7.2.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel
Ian Campbell writes ("Re: [Xen-devel] [PATCH 02/15] libxenstore: Provide xs_check_watch"):> Are we supposed to do something to the SONAME with this kind of change?Good point. I think that the MINOR should change since the change is backwards- but not forwards-compatible. So I have updated (in my tree) the MINOR and will add your ack. Thanks, Ian.
Ian Jackson
2011-Dec-08 17:32 UTC
Re: [PATCH 04/15] libxl: idl: support new "private" type attribute
Ian Campbell writes ("Re: [Xen-devel] [PATCH 04/15] libxl: idl: support new "private" type attribute"):> Acked-by: Ian Campbell <ian.campbell@citrix.com> > > iff you remove the stray print sys.stderr in the last hunk.Oops, done, thanks. Ian.
Ian Jackson
2011-Dec-08 18:16 UTC
Re: [PATCH 06/15] libxl: permit declaration after statement
Ian Campbell writes ("Re: [Xen-devel] [PATCH 06/15] libxl: permit declaration after statement"):> I''m happy with this so far as it goes but I was wondering where the > original -Wdeclaration-after-statement came from, do we actually mean > "-std=c99" or something along those lines?gcc -O1 -fno-omit-frame-pointer -m32 -march=i686 -g -fno-strict-aliasing -std=gnu99 -Wall -Wstrict-prototypes -Wno-unused-value -Wdeclaration-after-statement -D__XEN_TOOLS__ -MMD -MF .libxl.o.d -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fno-optimize-sibling-calls -mno-tls-direct-seg-refs -Werror -Wno-format-zero-length -Wmissing-declarations -I. -fPIC -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/libxc -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/libxc -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/xenstore -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/wor k/2/xen-unstable.git/tools/libxl/../../tools/blktap2/control -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/blktap2/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -c -o libxl.o libxl.c So cutting that down to the relevant bits: gcc ... -std=gnu99 -Wall ... -Wdeclaration-after-statement ... -Werror ... The -Wdeclaration-after-statement comes from Config.mk: $(call cc-option-add,HOSTCFLAGS,HOSTCC,-Wdeclaration-after-statement) $(call cc-option-add,CFLAGS,CC,-Wdeclaration-after-statement) So I think that since what we''re doing is having a different rule for libxl, it''s right to put it in libxl''s makefile. Ian.
Ian Jackson
2011-Dec-08 19:13 UTC
Re: [PATCH 12/15] libxl: Use GC_INIT and GC_FREE everywhere
Ian Campbell writes ("Re: [Xen-devel] [PATCH 12/15] libxl: Use GC_INIT and GC_FREE everywhere"):> On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote: > > GC_FREE; > > I suppose this really relates to the earlier patch which adds these > macros but wouldn''t "GC_FREE();" be nicer?I don''t normally write zero-adic statement macros that way. I guess this is just one of those stylistic points like whether to put parens around the argument to return. We don''t currently have any other zero-adic statement macros in libxl, nor any macros which depend on or introduce names in the caller''s namespace, apart from those we inherit from flex. My personal view is that non-hygienic statement macros are unusual enough that it''s worth drawing attention to them by using a special syntax. After all, their semantics are not normally very like functions because they refer to objects, including local variables, not explicitly named in the call. Often they declare variables or labels, and those kinds of statements don''t contain any (). So I think the empty () are misleading - they hint that the thing is a function, when it really isn''t enough like a function. In the rest of the xen tree we seem to have these without the "()" [1]: tools/libxen/test/test_event_handling.c: CLEANUP; tools/blktap2/drivers/lock.c: XSLEEP; and these with the "()" [2]: xen/drivers/acpi/osl.c: BUG(); xen/arch/ia64/asm-offsets.c: BLANK(); xen/common/inflate.c: NEXTBYTE(); Of these: CLEANUP non-hygienic block NEXTBYTE() non-hygienic block wrapped up in () to make it an expression XSLEEP hygienic expression (a call to usleep) BUG() hygienic expression (a call to asm) BLANK() something in some kind of table, not really relevant here This doesn''t seem to provide any consistent rule. Perhaps the right answer is a patch to the coding standard. One option for this below. This is a bit of a bikeshed issue of course. Ian. [1] find * -name \*.c | xargs egrep ''^[ ]*[A-Z][A-Z]*\;'' |less [2] find * -name \*.c | xargs egrep ''^[ ]*[A-Z][A-Z]*\(\)'' |less in both cases only one hit per macro mentioned diff --git a/tools/libxl/CODING_STYLE b/tools/libxl/CODING_STYLE index 110a48f..69fedb9 100644 --- a/tools/libxl/CODING_STYLE +++ b/tools/libxl/CODING_STYLE @@ -133,3 +133,25 @@ Rationale: a consistent (except for functions...) bracing style reduces ambiguity and avoids needless churn when lines are added or removed. Furthermore, it is the libxenlight coding style. + +6. Macros + +Naturally, macros (other than function-like ones which can be used +just like functions eg evaluate their arguments each exactly once +etc.) should be named in ALL_CAPITALS. Expansions, and references to +arguments should be protected with appropriate ( ), and code +with appropriate do{ ... }while(0) blocks. + +A zero-argument macro which expands to a non-constant expression, or +to an ordinary block, should be defined with empty parens like this: + #define MACRO() .... + +A zero-argument macro which expands to a constant expression; or whose +expansion relies on (or introduces) declarations, labels, etc., in the +containing scope; or which expands to another kind of code fragment, +should be defined like this: + #define MACRO ... + +Macros expanding to declarations and/or statements should not include +any trailing ";" so that they may be used like this: + MACRO(arguments);
Ian Jackson
2011-Dec-08 19:15 UTC
Re: [PATCH 13/15] libxl: make LIBXL_INIT_GC a statement, not an initialiser
Ian Campbell writes ("Re: [Xen-devel] [PATCH 13/15] libxl: make LIBXL_INIT_GC a statement, not an initialiser"):> On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote: > > In fact there is only one caller now, GC_INIT, > > Maybe we should just fold LIBXL_INIT_GC into GC_INIT then?No, because GC_INIT is a non-hygienic convenience macro. Such things should never be the only implementation of some important interface, because then if for any reason the lack of hygiene is a problem for you you are stuck. LIBXL_INIT_GC is the underlying functionality which may need to be used in those other, less usual cases, and therefore still needs to exist as a separate interface. Indeed in my asynchronous operations code (patch(es) still very much a work in progress) I will need to call LIBXL_INIT_GC outside GC_INIT. Ian.
Ian Campbell writes ("Re: [Xen-devel] [PATCH v4 00/15] New event API"):> I think I have now acked #1-11 either previously or just now, although > my comment on #12 really is about #7 so having either dismissed or > implemented that suggestion I''ve effectively acked #1-12.Given the bikeshed nature of your comment on #7 (GC_FREE) I''ll wait and see what develops from my recent posting. I''d rather not go through and commit another seddery in xen-unstable mainline... I''ll repost 01-06 in their now-hopefully-final form and hopefully apply them along with some of the rest of the backlog tomorrow. Ian.
Ian Jackson
2011-Dec-08 19:53 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Ian Campbell writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote: > > #include <libxl_uuid.h> > > +#include <_libxl_list.h> > > Do we expose the use of these to users anywhere? I''ve failed to spot it > if so (at least in this patch). If it is deliberate then #3 needs to > install this header.Oh. Yes, it is deliberate. There is a list link in libxl_event. I will arrange to install the header.> > +#include <libxl_event.h> > > Putting this at the end is a bit odd, I don''t really object though. I > suppose it depends on stuff defined in this header and putting it half > way through is even more odd.Exactly. This seems the best approach.> > @@ -0,0 +1,711 @@ > > +/* > > + * Copyright (C) 2011 Citrix Ltd. > > + * > > + * 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. > > I''ve only just noticed this but it is present in some other libxl files > too. There is no LICENSE file in tools/libxl: > $ find -name LICENSE > ./tools/ioemu-remote/LICENSE > ./tools/ioemu-remote/tcg/LICENSE > ./tools/ocaml/LICENSE > ./xen/tools/figlet/LICENSE > > I suspect this is a cut-and-paste-o, probably from tools/ocaml?All the existing files in libxl/ mention this nonexistent file LICENCE. I think we should fix this in a separate patch. I''d argue that my copying of the existing text isn''t making the situation worse.> > + * The application''s registration hooks should be called ONLY via > > + * these macros, with the ctx locked. Likewise all the "occurred" > > + * entrypoints from the application should assert(!in_hook); > > In RFC speak you mean MUST rather than should both times here, right?In the immortal words of RFC2181: 3. Terminology This memo does not use the oft used expressions MUST, SHOULD, MAY, or their negative forms. In some sections it may seem that a specification is worded mildly, and hence some may infer that the specification is optional. That is not correct. Anywhere that this memo suggests that some action should be carried out, or must be carried out, or that some behaviour is acceptable, or not, that is to be considered as a fundamental aspect of this specification, regardless of the specific words used. If some behaviour or action is truly optional, that will be clearly specified by the text. If you think this is confusing I can change it to "must"...> > +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, > > + libxl__ev_fd_callback *func, > > + int fd, short events) { > > Strictly speaking CODING_STYLE requires the { to be on the next line.Oh, I probably have a lot of those. Damn. I''ll try to remember to fix this up with some seddery somehow.> > + LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry); > > + > > + ev->fd = fd; > > + ev->events = events; > > + ev->in_beforepolled = -1; > > + ev->func = func; > > Even though this is all locked correctly seeing the ev initialised after > it is already on the list has tweaked my "what''s up" instinct such that > I''ve had to look twice both times I''ve looked at this patch.I''ll swap it round.> > + out: > > + CTX_UNLOCK; > > + return 0; > > You mean "return rc" here.So I do. Fixed here and in libxl__ev_time_modify_rel.> > +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev, > > + struct timeval abs) { > > + int rc; > > + > > + CTX_LOCK; > > + > > + assert(libxl__ev_time_isregistered(ev)); > > Why is there no deregister here? Is libxl__ev_time_modify_rel the only > caller?It''s currently the only caller but other bits of libxl are entitled to call it. It''s part of the facilities supplied to the rest of libxl. There is no deregister because (a) we don''t want to do that until we''ve called the hook, if necessary, in case the hook fails and (b) we have to explicitly deal with the two different cases: 1. existing event was infinite timeout, so not on queue, just call register_finite which will do everything needed 2. existing event _wasn''t_ infinite timeout, first call modify hook, then fiddle about with the queue> > + const char *epath = event[0]; > > + const char *token = event[1]; > > + int slotnum; > > + uint32_t counterval; > > + int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval); > > How have I never come across the SCNxxx counterpart to PRIxxx before!Hardly anyone ever uses scanf.> > + /* Now it''s possible, though unlikely, that this was an event > > + * from a previous use of the same slot with the same counterval. > > + * > > + * In that case either: > > + * - the event path is a child of the watch path, in > > + * which case this watch would really have generated this > > + * event if it had been registered soon enough and we are > > + * OK to give this possibly-spurious event to the caller; or > > + * - it is not, in which case we must suppress it as the > > + * caller should not see events for unrelated paths. > > + * > > + * See also docs/misc/xenstore.txt. > > + */ > > + size_t epathlen = strlen(epath); > > + size_t wpathlen = strlen(w->path); > > + if (epathlen < wpathlen || > > + memcmp(epath, w->path, wpathlen) || > > + (epathlen > wpathlen && epath[wpathlen] != ''/'')) { > > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > > + "watch epath=%s token=%s: not child of wpath=%s", > > + epath, token, w->path); > > It seems like this is worthy of a helper function of its own. Possibly > in libxenstore itself?You mean "int xs_path_is_subpath_p(const char *parent, const char *child)" ? Possibly. I wouldn''t be opposed to putting those 5 lines in libxenstore it there but AFAIK only this place in libxl needs it.> > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > > + "watch event: epath=%s token=%s wpath=%s w=%p", > > + epath, token, w->path, w); > > Aside: At some point we might want to have a way to configure classes of > debug log message on/off. I was just wondering if this message might be > a bit spammy but I suspect it is ok.I don''t think there will be that many of these. If so then yes we may need a more sophisticated debug framework.> > + use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots); > > + assert(use); > > + LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty); > > I presume this is removing "use" from the list. It seems odd to refer to > that element of the list as HEAD and FIRST interchangeably since it > doesn''t make this obvious but I guess we got this API from elsewhere.Yes, FreeBSD.> There''s no get-and-return function which combines the two operations?Not in this pile of macros, I''m afraid.> > + w->slotnum = slotnum; > > + w->path = path_copy; > > + w->callback = func; > > + /* we look a bit behind the curtain of LIBXL_SLIST, to explictly > > explicitlyFixed.> > + * assign to the pointer that''s the next link. See the comment > > + * by the definitionn of libxl__ev_watch_slot */ > > definition.Fixed.> I think this behind the curtain stuff would be better encapsulated in a > macro up somewhere near the comment and libxl__ev_watch_slot. > > > + use->empty.sle_next = (void*)w;How about: static void libxl__set_watch_slot_contents(libxl__ev_watch_slot *slot, libxl__ev_xswatch *w) { /* we look a bit behind the curtain of LIBXL_SLIST, to explicitly * assign to the pointer that''s the next link. See the comment * by the definition of libxl__ev_watch_slot */ slot->empty.sle_next = (void*)w; } Just below the the definition of libxl__watch_slot_contents. That puts it near the other big comment and it''s essentially the sister function.> > + CTX_LOCK; > > + > > + if (w->slotnum >= 0) { > > + char *token = watch_token(gc, w->slotnum, w->counterval); > > + if (!xs_unwatch(CTX->xsh, w->path, token)) > > + /* Oh well, we will just get watch events forever more > > + * and ignore them. But we should complain to the log. */ > > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, > > + "remove watch for path %s", w->path); > > Is it possible to also unwatch an unexpected watch at the point it > fires, IOW to try again later? I havn''et looked at the potential failure > cases of xs_unwatch so perhaps once it has failed there is no point in > trying again.Offhand I think it can fail because: - communication with xenstore has broken down, in which case trying again is pretty pointless - xenstore didn''t recognise the watch (ie we or xenstore have a bug) in which case trying to remove it is not sensible I''m also not sure exactly about the race implications. What if you add and remove watches in different threads simultaneously ? So I think this is probably best - and it''s probably best not to do additional complicated flailing when either (a) things are already going wrong or (b) we just got a harmless lost race.> This seems like a good place to stop for the day. I''ll pickup the rest > tomorrow.Heh. I should go to the pub :-). Ian.
On Thu, 2011-12-08 at 19:25 +0000, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH v4 00/15] New event API"): > > I think I have now acked #1-11 either previously or just now, although > > my comment on #12 really is about #7 so having either dismissed or > > implemented that suggestion I''ve effectively acked #1-12. > > Given the bikeshed nature of your comment on #7 (GC_FREE) I''ll wait > and see what develops from my recent posting. I''d rather not go > through and commit another seddery in xen-unstable mainline...You replies to #12 & #13 seem reasonable to me so you can consider #1-#13 acked.> I''ll repost 01-06 in their now-hopefully-final form and hopefully > apply them along with some of the rest of the backlog tomorrow. > > Ian.
Ian Campbell
2011-Dec-08 20:40 UTC
Re: [PATCH 06/15] libxl: permit declaration after statement
On Thu, 2011-12-08 at 18:16 +0000, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH 06/15] libxl: permit declaration after statement"): > > I''m happy with this so far as it goes but I was wondering where the > > original -Wdeclaration-after-statement came from, do we actually mean > > "-std=c99" or something along those lines? > > gcc -O1 -fno-omit-frame-pointer -m32 -march=i686 -g -fno-strict-aliasing -std=gnu99 -Wall -Wstrict-prototypes -Wno-unused-value -Wdeclaration-after-statement -D__XEN_TOOLS__ -MMD -MF .libxl.o.d -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fno-optimize-sibling-calls -mno-tls-direct-seg-refs -Werror -Wno-format-zero-length -Wmissing-declarations -I. -fPIC -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/libxc -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/libxc -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/xenstore -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/blktap2/control -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/blktap2/include -I/u/iwj/work/2/xen-unstable.git/tools/libxl/../../tools/include -c -o libxl.o libxl.c> > So cutting that down to the relevant bits: > > gcc ... -std=gnu99 -Wall ... -Wdeclaration-after-statement ... -Werror ... > > The -Wdeclaration-after-statement comes from Config.mk: > > $(call cc-option-add,HOSTCFLAGS,HOSTCC,-Wdeclaration-after-statement) > $(call cc-option-add,CFLAGS,CC,-Wdeclaration-after-statement) > > So I think that since what we''re doing is having a different rule for > libxl, it''s right to put it in libxl''s makefile.Agreed, I didn''t realise this warning came from a different bit of Xen''s build machinery. Ian.
Ian Campbell
2011-Dec-09 09:16 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Thu, 2011-12-08 at 19:53 +0000, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"): > > > @@ -0,0 +1,711 @@ > > > +/* > > > + * Copyright (C) 2011 Citrix Ltd. > > > + * > > > + * 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. > > > > I''ve only just noticed this but it is present in some other libxl files > > too. There is no LICENSE file in tools/libxl: > > $ find -name LICENSE > > ./tools/ioemu-remote/LICENSE > > ./tools/ioemu-remote/tcg/LICENSE > > ./tools/ocaml/LICENSE > > ./xen/tools/figlet/LICENSE > > > > I suspect this is a cut-and-paste-o, probably from tools/ocaml? > > All the existing files in libxl/ mention this nonexistent file > LICENCE. I think we should fix this in a separate patch. I''d argue > that my copying of the existing text isn''t making the situation worse.Sure, I didn''t mean to suggest you needed to fix this in this series, I just happened to observe it here.> > > + * The application''s registration hooks should be called ONLY via > > > + * these macros, with the ctx locked. Likewise all the "occurred" > > > + * entrypoints from the application should assert(!in_hook); > > > > In RFC speak you mean MUST rather than should both times here, right? > > In the immortal words of RFC2181: > > 3. Terminology > > This memo does not use the oft used expressions MUST, SHOULD, MAY, or > their negative forms. In some sections it may seem that a > specification is worded mildly, and hence some may infer that the > specification is optional. That is not correct. Anywhere that this > memo suggests that some action should be carried out, or must be > carried out, or that some behaviour is acceptable, or not, that is to > be considered as a fundamental aspect of this specification, > regardless of the specific words used. If some behaviour or action > is truly optional, that will be clearly specified by the text. > > If you think this is confusing I can change it to "must"...I was mainly asking just to clarify my own understanding, as you point out we don''t use those "oft used expressions" in our comments.> > > +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, > > > + libxl__ev_fd_callback *func, > > > + int fd, short events) { > > > > Strictly speaking CODING_STYLE requires the { to be on the next line. > > Oh, I probably have a lot of those. Damn.Yeah, I refrained from commenting every time ;-)> I''ll try to remember to > fix this up with some seddery somehow.[...]> > > +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev, > > > + struct timeval abs) { > > > + int rc; > > > + > > > + CTX_LOCK; > > > + > > > + assert(libxl__ev_time_isregistered(ev)); > > > > Why is there no deregister here? Is libxl__ev_time_modify_rel the only > > caller? > > It''s currently the only caller but other bits of libxl are entitled to > call it. It''s part of the facilities supplied to the rest of libxl. > > There is no deregister because (a) we don''t want to do that until > we''ve called the hook, if necessary, in case the hook fails and (b) we > have to explicitly deal with the two different cases: > 1. existing event was infinite timeout, so not on queue, just > call register_finite which will do everything needed > 2. existing event _wasn''t_ infinite timeout, first call modify > hook, then fiddle about with the queueThanks, I was confused by the presence of a register/insert without a corresponding unregister/delete but I see now that in one case the ev isn''t registered by definition (the infinite->finite case) and the other you do actually remove it from the list (I missed that somehow). [...]> > > + /* Now it''s possible, though unlikely, that this was an event > > > + * from a previous use of the same slot with the same counterval. > > > + * > > > + * In that case either: > > > + * - the event path is a child of the watch path, in > > > + * which case this watch would really have generated this > > > + * event if it had been registered soon enough and we are > > > + * OK to give this possibly-spurious event to the caller; or > > > + * - it is not, in which case we must suppress it as the > > > + * caller should not see events for unrelated paths. > > > + * > > > + * See also docs/misc/xenstore.txt. > > > + */ > > > + size_t epathlen = strlen(epath); > > > + size_t wpathlen = strlen(w->path); > > > + if (epathlen < wpathlen || > > > + memcmp(epath, w->path, wpathlen) || > > > + (epathlen > wpathlen && epath[wpathlen] != ''/'')) { > > > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > > > + "watch epath=%s token=%s: not child of wpath=%s", > > > + epath, token, w->path); > > > > It seems like this is worthy of a helper function of its own. Possibly > > in libxenstore itself? > > You mean "int xs_path_is_subpath_p(const char *parent, const char *child)" ? > > Possibly. I wouldn''t be opposed to putting those 5 lines in > libxenstore it there but AFAIK only this place in libxl needs it.Wouldn''t most users of libxenstore doing watches need something like this (and probably either open code it or erroneously omit it)? Regardless of where it goes moving that logic into a helper function will make it clearer what is going on, both by having a descriptive name and allowing the logic to be a bit more spaced out / commented, the last clause in particular is slightly subtle.> > > + use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots); > > > + assert(use); > > > + LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty); > > > > I presume this is removing "use" from the list. It seems odd to refer to > > that element of the list as HEAD and FIRST interchangeably since it > > doesn''t make this obvious but I guess we got this API from elsewhere. > > Yes, FreeBSD.Sorry, I knew that, I was trying to say "we got this API from elsewhere so I guess we have to live with its quirks".> > I think this behind the curtain stuff would be better encapsulated in a > > macro up somewhere near the comment and libxl__ev_watch_slot. > > > > > + use->empty.sle_next = (void*)w; > > How about: > > static void libxl__set_watch_slot_contents(libxl__ev_watch_slot *slot, > libxl__ev_xswatch *w) { > /* we look a bit behind the curtain of LIBXL_SLIST, to explicitly > * assign to the pointer that''s the next link. See the comment > * by the definition of libxl__ev_watch_slot */ > slot->empty.sle_next = (void*)w; > } > > Just below the the definition of libxl__watch_slot_contents. That > puts it near the other big comment and it''s essentially the sister > function.Works for me.> > > > + CTX_LOCK; > > > + > > > + if (w->slotnum >= 0) { > > > + char *token = watch_token(gc, w->slotnum, w->counterval); > > > + if (!xs_unwatch(CTX->xsh, w->path, token)) > > > + /* Oh well, we will just get watch events forever more > > > + * and ignore them. But we should complain to the log. */ > > > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, > > > + "remove watch for path %s", w->path); > > > > Is it possible to also unwatch an unexpected watch at the point it > > fires, IOW to try again later? I havn''et looked at the potential failure > > cases of xs_unwatch so perhaps once it has failed there is no point in > > trying again. > > Offhand I think it can fail because: > - communication with xenstore has broken down, in which case trying > again is pretty pointless > - xenstore didn''t recognise the watch (ie we or xenstore have a bug) > in which case trying to remove it is not sensible > I''m also not sure exactly about the race implications. What if you > add and remove watches in different threads simultaneously ?We are holding a lock at this point, I''m not sure if this is just because of the associated datastructure frobbing or if their is an (implicit or explicit) policy of holding the lock when adding or removing watches.> So I think this is probably best - and it''s probably best not to do > additional complicated flailing when either (a) things are already > going wrong or (b) we just got a harmless lost race.I''m convinced, thanks.> > This seems like a good place to stop for the day. I''ll pickup the rest > > tomorrow. > > Heh. I should go to the pub :-).Always a good call. Ian.
Stefano Stabellini
2011-Dec-09 11:34 UTC
Re: [PATCH 06/15] libxl: permit declaration after statement
On Wed, 7 Dec 2011, Ian Campbell wrote:> On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote: > > GCC and C99 allow declarations to be mixed with code. This is a good > > idea because: > > > > * It allows variables to be more often initialised as they are > > declared, thus reducing the occurrence of uninitialised variable > > errors. > > > > * Certain alloca-like constructs (arrays allocated at runtime on the > > stack) can more often be written without a spurious { } block. > > Such blocks are confusing to read. > > > > * It makes it easier to write and use macros which declare and > > initialise formulaic variables and do other function setup code, > > because there is no need to worry that such macros might be > > incompatible with each other or have strict ordering constraints. > > > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> > > I''m happy with this so far as it goes but I was wondering where the > original -Wdeclaration-after-statement came from, do we actually mean > "-std=c99" or something along those lines? > > Anyway I''m still ok with saying: > Acked-by: Ian Campbell <ian.campbell@citrix.com>Of course I still think that it is the wrong decision, but unfortunately it seems that I am outnumbered on this. Policy changes like this one, do the need the majority or unanimity? :-)
Stefano Stabellini
2011-Dec-09 15:44 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Mon, 5 Dec 2011, Ian Jackson wrote:> We provide a new set of functions and related structures > libxl_osevent_* > which are to be used by event-driven applications to receive > information from libxl about which fds libxl is interested in, and > what timeouts libxl is waiting for, and to pass back to libxl > information about which fds are readable/writeable etc., and which > timeouts have occurred. Ie, low-level events. > > In this patch, this new machinery is still all unused. Callers will > appear in the next patch in the series, which introduces a new API for > applications to receive high-level events about actual domains etc. > > Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> > --- > tools/libxl/Makefile | 2 +- > tools/libxl/libxl.c | 25 ++ > tools/libxl/libxl.h | 6 + > tools/libxl/libxl_event.c | 711 ++++++++++++++++++++++++++++++++++++++++++ > tools/libxl/libxl_event.h | 199 ++++++++++++ > tools/libxl/libxl_internal.h | 216 +++++++++++++- > 6 files changed, 1155 insertions(+), 4 deletions(-) > create mode 100644 tools/libxl/libxl_event.c > create mode 100644 tools/libxl/libxl_event.h > > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile > index 4e0f3fb..3d575b8 100644 > --- a/tools/libxl/Makefile > +++ b/tools/libxl/Makefile > @@ -38,7 +38,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_qmp.o $(LIBXL_OBJS-y) > + libxl_qmp.o libxl_event.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 3a8cfe3..58f280c 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -60,6 +60,16 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > * only as an initialiser, not as an expression. */ > memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); > > + ctx->osevent_hooks = 0; > + > + ctx->fd_beforepolled = 0; > + LIBXL_LIST_INIT(&ctx->efds); > + LIBXL_TAILQ_INIT(&ctx->etimes); > + > + ctx->watch_slots = 0; > + LIBXL_SLIST_INIT(&ctx->watch_freeslots); > + libxl__ev_fd_init(&ctx->watch_efd); > + > if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { > LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" > "failed to stat %s", XENSTORE_PID_FILE); > @@ -89,10 +99,25 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > > int libxl_ctx_free(libxl_ctx *ctx) > { > + int i; > + GC_INIT(ctx); > + > if (!ctx) return 0; > + > + for (i = 0; i < ctx->watch_nslots; i++) > + assert(!libxl__watch_slot_contents(gc, i)); > + libxl__ev_fd_deregister(gc, &ctx->watch_efd); > + > + assert(LIBXL_LIST_EMPTY(&ctx->efds)); > + assert(LIBXL_TAILQ_EMPTY(&ctx->etimes)); > + > if (ctx->xch) xc_interface_close(ctx->xch); > libxl_version_info_dispose(&ctx->version_info); > if (ctx->xsh) xs_daemon_close(ctx->xsh); > + > + free(ctx->fd_beforepolled); > + free(ctx->watch_slots); > + > return 0; > } > > diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h > index 289dc85..654a5b0 100644 > --- a/tools/libxl/libxl.h > +++ b/tools/libxl/libxl.h > @@ -137,6 +137,7 @@ > #include <xen/sysctl.h> > > #include <libxl_uuid.h> > +#include <_libxl_list.h> > > typedef uint8_t libxl_mac[6]; > #define LIBXL_MAC_FMT "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx" > @@ -222,6 +223,9 @@ enum { > ERROR_BADFAIL = -7, > ERROR_GUEST_TIMEDOUT = -8, > ERROR_TIMEDOUT = -9, > + ERROR_NOT_READY = -10, > + ERROR_OSEVENT_REG_FAIL = -11, > + ERROR_BUFFERFULL = -12, > }; > > #define LIBXL_VERSION 0 > @@ -635,6 +639,8 @@ const char *libxl_lock_dir_path(void); > const char *libxl_run_dir_path(void); > const char *libxl_xenpaging_dir_path(void); > > +#include <libxl_event.h> > + > #endif /* LIBXL_H */ > > /* > diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c > new file mode 100644 > index 0000000..8d4dbf6 > --- /dev/null > +++ b/tools/libxl/libxl_event.c > @@ -0,0 +1,711 @@ > +/* > + * Copyright (C) 2011 Citrix Ltd. > + * > + * 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. > + */ > +/* > + * Internal event machinery for use by other parts of libxl > + */ > + > +#include <poll.h> > + > +#include "libxl_internal.h" > + > +/* > + * The counter osevent_in_hook is used to ensure that the application > + * honours the reentrancy restriction documented in libxl_event.h. > + * > + * The application''s registration hooks should be called ONLY via > + * these macros, with the ctx locked. Likewise all the "occurred" > + * entrypoints from the application should assert(!in_hook); > + */ > +#define OSEVENT_HOOK_INTERN(defval, hookname, ...) \ > + (CTX->osevent_hooks \ > + ? (CTX->osevent_in_hook++, \ > + CTX->osevent_hooks->hookname(CTX->osevent_user, __VA_ARGS__), \ > + CTX->osevent_in_hook--) \ > + : defval) > + > +#define OSEVENT_HOOK(hookname,...) \ > + OSEVENT_HOOK_INTERN(0, hookname, __VA_ARGS__) > + > +#define OSEVENT_HOOK_VOID(hookname,...) \ > + OSEVENT_HOOK_INTERN((void)0, hookname, __VA_ARGS__)Is there any reasons why we cannot use static inline functions here?> +/* > + * fd events > + */ > + > +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, > + libxl__ev_fd_callback *func, > + int fd, short events) { > + int rc; > + > + assert(fd >= 0); > + > + CTX_LOCK; > + > + rc = OSEVENT_HOOK(fd_register, fd, &ev->for_app_reg, events, ev); > + if (rc) goto out; > + > + LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry); > + > + ev->fd = fd; > + ev->events = events; > + ev->in_beforepolled = -1; > + ev->func = func; > + > + rc = 0; > + > + out: > + CTX_UNLOCK; > + return rc; > +} > + > +int libxl__ev_fd_modify(libxl__gc *gc, libxl__ev_fd *ev, short events) { > + int rc; > + > + CTX_LOCK; > + assert(libxl__ev_fd_isregistered(ev)); > + > + rc = OSEVENT_HOOK(fd_modify, ev->fd, &ev->for_app_reg, events); > + if (rc) goto out; > + > + ev->events = events; > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return rc; > +} > + > +void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev) { > + CTX_LOCK; > + > + if (!libxl__ev_fd_isregistered(ev)) > + goto out; > + > + OSEVENT_HOOK_VOID(fd_deregister, ev->fd, ev->for_app_reg); > + LIBXL_LIST_REMOVE(ev, entry); > + ev->fd = -1; > + > + if (ev->in_beforepolled >= 0 && > + ev->in_beforepolled < CTX->fd_beforepolled_used) > + /* remove stale reference */ > + CTX->fd_beforepolled[ev->in_beforepolled] = NULL; > + > + out: > + CTX_UNLOCK; > +} > + > +/* > + * timeouts > + */ > + > + > +int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r) { > + int rc = gettimeofday(now_r, 0); > + if (rc) { > + LIBXL__LOG_ERRNO(CTX, LIBXL__LOG_ERROR, "gettimeofday failed"); > + return ERROR_FAIL; > + } > + return 0; > +} > + > +static int time_rel_to_abs(libxl__gc *gc, int ms, struct timeval *abs_out) { > + int rc; > + struct timeval additional = { > + .tv_sec = ms / 1000, > + .tv_usec = (ms % 1000) * 1000 > + }; > + struct timeval now; > + > + rc = libxl__gettimeofday(gc, &now); > + if (rc) return rc; > + > + timeradd(&now, &additional, abs_out); > + return 0; > +} > + > +static void time_insert_finite(libxl__gc *gc, libxl__ev_time *ev) { > + libxl__ev_time *evsearch; > + LIBXL_TAILQ_INSERT_SORTED(&CTX->etimes, entry, ev, evsearch, , > + timercmp(&ev->abs, &evsearch->abs, >)); > + ev->infinite = 0; > +} > + > +static int time_register_finite(libxl__gc *gc, libxl__ev_time *ev, > + struct timeval abs) { > + int rc; > + > + rc = OSEVENT_HOOK(timeout_register, &ev->for_app_reg, abs, ev); > + if (rc) return rc; > + > + ev->infinite = 0; > + ev->abs = abs; > + time_insert_finite(gc, ev); > + > + return 0; > +} > + > +static void time_deregister(libxl__gc *gc, libxl__ev_time *ev) { > + if (!ev->infinite) { > + OSEVENT_HOOK_VOID(timeout_deregister, &ev->for_app_reg); > + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); > + } > +} > + > + > +int libxl__ev_time_register_abs(libxl__gc *gc, libxl__ev_time *ev, > + libxl__ev_time_callback *func, > + struct timeval abs) { > + int rc; > + > + CTX_LOCK; > + > + rc = time_register_finite(gc, ev, abs); > + if (rc) goto out; > + > + ev->func = func; > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return rc; > +} > + > + > +int libxl__ev_time_register_rel(libxl__gc *gc, libxl__ev_time *ev, > + libxl__ev_time_callback *func, > + int milliseconds /* as for poll(2) */) { > + struct timeval abs; > + int rc; > + > + CTX_LOCK; > + > + if (milliseconds < 0) { > + ev->infinite = 1; > + } else { > + rc = time_rel_to_abs(gc, milliseconds, &abs); > + if (rc) goto out; > + > + rc = time_register_finite(gc, ev, abs); > + if (rc) goto out; > + } > + > + ev->func = func; > + rc = 0; > + > + out: > + CTX_UNLOCK; > + return 0; > +} > + > +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev, > + struct timeval abs) { > + int rc; > + > + CTX_LOCK; > + > + assert(libxl__ev_time_isregistered(ev)); > + > + if (ev->infinite) { > + rc = time_register_finite(gc, ev, abs); > + if (rc) goto out; > + } else { > + rc = OSEVENT_HOOK(timeout_modify, &ev->for_app_reg, abs); > + if (rc) goto out; > + > + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); > + ev->abs = abs; > + time_insert_finite(gc, ev); > + } > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return rc; > +} > + > +int libxl__ev_time_modify_rel(libxl__gc *gc, libxl__ev_time *ev, > + int milliseconds) { > + struct timeval abs; > + int rc; > + > + CTX_LOCK; > + > + assert(libxl__ev_time_isregistered(ev)); > + > + if (milliseconds < 0) { > + time_deregister(gc, ev); > + ev->infinite = 1; > + rc = 0; > + goto out; > + } > + > + rc = time_rel_to_abs(gc, milliseconds, &abs); > + if (rc) goto out; > + > + rc = libxl__ev_time_modify_abs(gc, ev, abs); > + if (rc) goto out; > + > + rc = 0; > + out: > + CTX_UNLOCK; > + return 0; > +} > + > +void libxl__ev_time_deregister(libxl__gc *gc, libxl__ev_time *ev) { > + CTX_LOCK; > + > + if (!libxl__ev_time_isregistered(ev)) > + goto out; > + > + time_deregister(gc, ev); > + ev->func = 0; > + > + out: > + CTX_UNLOCK; > + return; > +} > + > + > +/* > + * xenstore watches > + */ > + > +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum) { > + libxl__ev_watch_slot *slot = &CTX->watch_slots[slotnum]; > + libxl__ev_watch_slot *slotcontents = LIBXL_SLIST_NEXT(slot, empty); > + > + if (slotcontents == NULL || > + ((uintptr_t)slotcontents >= (uintptr_t)CTX->watch_slots && > + (uintptr_t)slotcontents < (uintptr_t)(CTX->watch_slots + > + CTX->watch_nslots))) > + /* An empty slot has either a NULL pointer (end of the > + * free list), or a pointer to another entry in the array. > + * So we can do a bounds check to distinguish empty from > + * full slots. > + */ > + /* We need to do the comparisons as uintptr_t because > + * comparing pointers which are not in the same object is > + * undefined behaviour; if the compiler managed to figure > + * out that watch_slots[0..watch_nslots-1] is all of the > + * whole array object it could prove that the above bounds > + * check was always true if it was legal, and remove it! > + * > + * uintptr_t because even on a machine with signed > + * pointers, objects do not cross zero; whereas on > + * machines with unsigned pointers, they may cross > + * 0x8bazillion. > + */ > + return NULL; > + > + /* see comment near libxl__ev_watch_slot definition */ > + return (void*)slotcontents; > +} > + > +static void watchfd_callback(libxl__gc *gc, libxl__ev_fd *ev, > + int fd, short events, short revents) { > + for (;;) { > + char **event = xs_check_watch(CTX->xsh); > + if (!event) { > + if (errno == EAGAIN) break; > + if (errno == EINTR) continue; > + LIBXL__EVENT_DISASTER(gc, "cannot check/read watches", errno, 0); > + return; > + } > + > + const char *epath = event[0]; > + const char *token = event[1]; > + int slotnum; > + uint32_t counterval;OK, this is the last time I am going to point this out, but epath, token, etc, should be declared above, at the beginning of the block.> + int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval); > + if (rc != 2) { > + LIBXL__LOG(CTX, LIBXL__LOG_ERROR, > + "watch epath=%s token=%s: failed to parse token", > + epath, token); > + /* oh well */ > + goto ignore; > + } > + if (slotnum < 0 || slotnum >= CTX->watch_nslots) { > + /* perhaps in the future we will make the watchslots array shrink */ > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, "watch epath=%s token=%s:" > + " slotnum %d out of range [0,%d>", > + epath, token, slotnum, CTX->watch_nslots); > + goto ignore; > + } > + > + libxl__ev_xswatch *w = libxl__watch_slot_contents(gc, slotnum); > + > + if (!w) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: empty slot", > + epath, token); > + goto ignore; > + } > + > + if (w->counterval != counterval) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: counter != %"PRIx32, > + epath, token, w->counterval); > + goto ignore; > + } > + > + /* Now it''s possible, though unlikely, that this was an event > + * from a previous use of the same slot with the same counterval. > + * > + * In that case either: > + * - the event path is a child of the watch path, in > + * which case this watch would really have generated this > + * event if it had been registered soon enough and we are > + * OK to give this possibly-spurious event to the caller; or > + * - it is not, in which case we must suppress it as the > + * caller should not see events for unrelated paths. > + * > + * See also docs/misc/xenstore.txt. > + */ > + size_t epathlen = strlen(epath); > + size_t wpathlen = strlen(w->path); > + if (epathlen < wpathlen || > + memcmp(epath, w->path, wpathlen) || > + (epathlen > wpathlen && epath[wpathlen] != ''/'')) { > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch epath=%s token=%s: not child of wpath=%s", > + epath, token, w->path); > + goto ignore; > + } > + > + /* At last, we have checked everything! */ > + LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, > + "watch event: epath=%s token=%s wpath=%s w=%p", > + epath, token, w->path, w); > + w->callback(gc, w, w->path, epath); > + > + ignore: > + free(event); > + } > +} > + > +static char *watch_token(libxl__gc *gc, int slotnum, uint32_t counterval) { > + return libxl__sprintf(gc, "%d/%"PRIx32, slotnum, counterval); > +} > + > +int libxl__ev_xswatch_register(libxl__gc *gc, libxl__ev_xswatch *w, > + libxl__ev_xswatch_callback *func, > + const char *path /* copied */) { > + libxl__ev_watch_slot *use = NULL; > + char *path_copy = NULL; > + int rc; > + > + CTX_LOCK; > + > + if (!libxl__ev_fd_isregistered(&CTX->watch_efd)) { > + rc = libxl__ev_fd_register(gc, &CTX->watch_efd, watchfd_callback, > + xs_fileno(CTX->xsh), POLLIN); > + if (rc) goto out_rc; > + } > + > + if (LIBXL_SLIST_EMPTY(&CTX->watch_freeslots)) { > + /* Free list is empty so there is not in fact a linked > + * free list in the array and we can safely realloc it */ > + int newarraysize = (CTX->watch_nslots + 1) << 2; > + int i; > + libxl__ev_watch_slot *newarray > + realloc(CTX->watch_slots, sizeof(*newarray) * newarraysize); > + if (!newarray) goto out_nomem; > + for (i=CTX->watch_nslots; i<newarraysize; i++)does not follow the CODING_STYLE, it should be for (i = CTX->watch_nslots; i < newarraysize; i++)> + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, > + &newarray[i], empty); > + CTX->watch_slots = newarray; > + CTX->watch_nslots = newarraysize; > + }would it make sense to move this code in its own allocate_watch_slots function?> + use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots); > + assert(use); > + LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty); > + > + path_copy = strdup(path); > + if (!path_copy) goto out_nomem; > + > + int slotnum = use - CTX->watch_slots; > + w->counterval = CTX->watch_counter++; > + > + if (!xs_watch(CTX->xsh, path, watch_token(gc, slotnum, w->counterval))) { > + LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno, > + "create watch for path %s", path); > + rc = ERROR_FAIL; > + goto out_rc; > + } > + > + w->slotnum = slotnum; > + w->path = path_copy; > + w->callback = func; > + /* we look a bit behind the curtain of LIBXL_SLIST, to explictly > + * assign to the pointer that''s the next link. See the comment > + * by the definitionn of libxl__ev_watch_slot */ > + use->empty.sle_next = (void*)w; > + > + CTX_UNLOCK; > + return 0; > + > + out_nomem: > + rc = ERROR_NOMEM; > + out_rc: > + if (use) > + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, use, empty); > + > + free(w->path); > + w->path = NULL; > + > + CTX_UNLOCK; > +} > + > +/* > + * osevent poll > + */ > + > +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > + struct pollfd *fds, int *timeout_upd, > + struct timeval now) { > + libxl__ev_fd *efd; > + int i; > + > + /* > + * In order to be able to efficiently find the libxl__ev_fd > + * for a struct poll during _afterpoll, we maintain a shadow > + * data structure in CTX->fd_beforepolled: each slot in > + * the fds array corresponds to a slot in fd_beforepolled. > + */ > + > + GC_INIT(ctx); > + CTX_LOCK; > + > + if (*nfds_io) { > + /* > + * As an optimisation, we don''t touch fd_beforepolled_used > + * if *nfds_io is zero on entry, since in that case the > + * caller just wanted to know how big an array to give us. > + * > + * If !*nfds_io, the unconditional parts below are guaranteed > + * not to mess with fd_beforepolled... or any in_beforepolled. > + */ > + > + /* Remove all the old references into beforepolled */ > + for (i = 0; i < CTX->fd_beforepolled_used; i++) { > + efd = CTX->fd_beforepolled[i]; > + if (efd) { > + assert(efd->in_beforepolled == i); > + efd->in_beforepolled = -1; > + CTX->fd_beforepolled[i] = NULL; > + } > + } > + CTX->fd_beforepolled_used = 0; > + > + /* make sure our array is as big as *nfds_io */ > + if (CTX->fd_beforepolled_allocd < *nfds_io) { > + assert(*nfds_io < INT_MAX / sizeof(libxl__ev_fd*) / 2); > + libxl__ev_fd **newarray > + realloc(CTX->fd_beforepolled, sizeof(*newarray) * *nfds_io); > + if (!newarray) > + return ERROR_NOMEM; > + CTX->fd_beforepolled = newarray; > + CTX->fd_beforepolled_allocd = *nfds_io; > + } > + } > + > + int used = 0; > + LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) { > + if (used < *nfds_io) { > + fds[used].fd = efd->fd; > + fds[used].events = efd->events; > + fds[used].revents = 0; > + CTX->fd_beforepolled[used] = efd; > + efd->in_beforepolled = used; > + } > + used++; > + } > + int rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL; > + > + if (*nfds_io) { > + CTX->fd_beforepolled_used = used; > + } > + > + *nfds_io = used; > + > + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); > + if (etime) { > + int our_timeout; > + struct timeval rel; > + static struct timeval zero; > + > + timersub(&etime->abs, &now, &rel); > + > + if (timercmp(&rel, &zero, <)) { > + our_timeout = 0; > + } else if (rel.tv_sec >= 2000000) { > + our_timeout = 2000000000; > + } else { > + our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000; > + } > + if (*timeout_upd < 0 || our_timeout < *timeout_upd) > + *timeout_upd = our_timeout; > + } > + > + CTX_UNLOCK; > + GC_FREE; > + return rc; > +} > + > +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, > + struct timeval now) { > + int i; > + GC_INIT(ctx); > + CTX_LOCK; > + > + assert(nfds <= CTX->fd_beforepolled_used); > + > + for (i = 0; i < nfds; i++) { > + if (!fds[i].revents) > + continue; > + > + libxl__ev_fd *efd = CTX->fd_beforepolled[i]; > + if (!efd) > + continue; > + > + assert(efd->in_beforepolled == i); > + assert(fds[i].fd == efd->fd); > + > + int revents = fds[i].revents & efd->events; > + if (!revents) > + continue; > + > + efd->func(gc, efd, efd->fd, efd->events, revents); > + } > + > + for (;;) { > + libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes); > + if (!etime) > + break; > + > + assert(!etime->infinite); > + > + if (timercmp(&etime->abs, &now, >)) > + break; > + > + time_deregister(gc, etime); > + > + etime->func(gc, etime, &etime->abs); > + } > + > + CTX_UNLOCK; > + GC_FREE; > +} > + > + > +/* > + * osevent hook and callback machinery > + */ > + > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > + const libxl_osevent_hooks *hooks, > + void *user) { > + GC_INIT(ctx); > + CTX_LOCK; > + ctx->osevent_hooks = hooks; > + ctx->osevent_user = user; > + CTX_UNLOCK; > + GC_FREE; > +} > + > + > +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl, > + int fd, short events, short revents) { > + libxl__ev_fd *ev = for_libxl; > + > + GC_INIT(ctx); > + CTX_LOCK; > + assert(!CTX->osevent_in_hook); > + > + assert(fd == ev->fd); > + revents &= ev->events; > + if (revents) > + ev->func(gc, ev, fd, ev->events, revents); > + > + CTX_UNLOCK; > + GC_FREE; > +} > + > +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl) { > + libxl__ev_time *ev = for_libxl; > + > + GC_INIT(ctx); > + CTX_LOCK; > + assert(!CTX->osevent_in_hook); > + > + assert(!ev->infinite); > + LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry); > + ev->func(gc, ev, &ev->abs); > + > + CTX_UNLOCK; > + GC_FREE; > +} > + > +void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval, > + libxl_event_type type /* may be 0 */, > + const char *file, int line, const char *func) { > + libxl__log(CTX, XTL_CRITICAL, errnoval, file, line, func, > + "DISASTER in event loop: %s%s%s%s", > + msg, > + type ? " (relates to event type " : "", > + type ? libxl_event_type_to_string(type) : "", > + type ? ")" : ""); > + > + /* > + * FIXME: This should call the "disaster" hook supplied to > + * libxl_event_register_callbacks, which will be introduced in the > + * next patch. > + */ > + > + const char verybad[] > + "DISASTER in event loop not handled by libxl application"; > + LIBXL__LOG(CTX, XTL_CRITICAL, verybad); > + fprintf(stderr, "libxl: fatal error, exiting program: %s\n", verybad); > + exit(-1); > +} > + > +/* > + * Local variables: > + * mode: C > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h > new file mode 100644 > index 0000000..25efbdf > --- /dev/null > +++ b/tools/libxl/libxl_event.h > @@ -0,0 +1,199 @@ > +/* > + * Copyright (C) 2011 Citrix Ltd. > + * Author Ian Jackson <ian.jackson@eu.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. > + */ > + > +#ifndef LIBXL_EVENT_H > +#define LIBXL_EVENT_H > + > +#include <libxl.h> > + > + > +/*======================================================================*/ > + > +/* > + * OS event handling - passing low-level OS events to libxl > + * > + * Event-driven programs must use these facilities to allow libxl > + * to become aware of readability/writeability of file descriptors > + * and the occurrence of timeouts. > + * > + * There are two approaches available. The first is appropriate for > + * simple programs handling reasonably small numbers of domains: > + * > + * for (;;) { > + * libxl_osevent_beforepoll(...) > + * poll(); > + * libxl_osevent_afterpoll(...); > + * for (;;) { > + * r=libxl_event_check(...); > + * if (r==LIBXL_NOT_READY) break; > + * if (r) handle failure; > + * do something with the event; > + * } > + * } > + * > + * The second approach uses libxl_osevent_register_hooks and is > + * suitable for programs which are already using a callback-based > + * event library. > + * > + * An application may freely mix the two styles of interaction. > + */ > + > +struct pollfd; > + > +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > + struct pollfd *fds, int *timeout_upd, > + struct timeval now); > + /* The caller should provide beforepoll with some space for libxl''s > + * fds, and tell libxl how much space is available by setting *nfds_io. > + * fds points to the start of this space (and fds may be a pointer into > + * a larger array, for example, if the application has some fds of > + * its own that it is interested in). > + * > + * On return *nfds_io will in any case have been updated by libxl > + * according to how many fds libxl wants to poll on. > + * > + * If the space was sufficient, libxl fills in fds[0..<new > + * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed, > + * and returns ok. > + * > + * If space was insufficient, fds[0..<old *nfds_io>] is undefined on > + * return; *nfds_io on return will be greater than the value on > + * entry; *timeout_upd may or may not have been updated; and > + * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this case > + * the application needs to make more space (enough space for > + * *nfds_io struct pollfd) and then call beforepoll again, before > + * entering poll(2). Typically this will involve calling realloc. > + * > + * The application may call beforepoll with fds==NULL and > + * *nfds_io==0 in order to find out how much space is needed. > + * > + * *timeout_upd is as for poll(2): it''s in milliseconds, and > + * negative values mean no timeout (infinity). > + * libxl_osevent_beforepoll will only reduce the timeout, naturally. > + */so far we have always added the comment on a function above the declaration of the function; we should keep doing it for consistency> +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, > + struct timeval now); > + /* nfds and fds[0..nfds] must be from the most recent call to > + * _beforepoll, as modified by poll. > + * > + * This function actually performs all of the IO and other actions, > + * and generates events (libxl_event), which are implied by either > + * (a) the time of day or (b) both (i) the returned information from > + * _beforepoll, and (ii) the results from poll specified in > + * fds[0..nfds-1]. Generated events can then be retrieved by > + * libxl_event_check. > + */ > +I see that the implementation of libxl_event_check is actually missing from this patch. Is this patch supposed to compiled, even without the actual libxl_event generation? Or are the two patches have to be committed together?> +typedef struct libxl_osevent_hooks { > + int (*fd_register)(void *uselibxl_event_check.r, int fd, void **for_app_registration_out, > + short events, void *for_libxl); > + int (*fd_modify)(void *user, int fd, void **for_app_registration_update, > + short events); > + void (*fd_deregister)(void *user, int fd, void *for_app_registration); > + int (*timeout_register)(void *user, void **for_app_registration_out, > + struct timeval abs, void *for_libxl); > + int (*timeout_modify)(void *user, void **for_app_registration_update, > + struct timeval abs); > + void (*timeout_deregister)(void *user, void *for_app_registration_io); > +} libxl_osevent_hooks; > + > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > + const libxl_osevent_hooks *hooks, > + void *user); > + /* The application which calls register_fd_hooks promises to > + * maintain a register of fds and timeouts that libxl is interested > + * in, and make calls into libxl (libxl_osevent_occurred_*) > + * when those fd events and timeouts occur. This is more efficient > + * than _beforepoll/_afterpoll if there are many fds (which can > + * happen if the same libxl application is managing many domains). > + * > + * For an fd event, events is as for poll(). register or modify may > + * be called with events==0, in which case it must still work > + * normally, just not generate any events. > + * > + * For a timeout event, milliseconds is as for poll(). > + * Specifically, negative values of milliseconds mean NO TIMEOUT. > + * This is used by libxl to temporarily disable a timeout. > + * > + * If the register or modify hook succeeds it may update > + * *for_app_registration_out/_update and must then return 0. > + * On entry to register, *for_app_registration_out is always NULL. > + * > + * A registration or modification hook may fail, in which case it > + * must leave the registration state of the fd or timeout unchanged. > + * It may then either return ERROR_OSEVENT_REG_FAIL or any positive > + * int. The value returned will be passed up through libxl and > + * eventually returned back to the application. When register > + * fails, any value stored into *for_registration_out is ignored by > + * libxl; when modify fails, any changed value stored into > + * *for_registration_update is honoured by libxl and will be passed > + * to future modify or deregister calls. > + * > + * libxl will only attempt to register one callback for any one fd. > + * libxl will remember the value stored in *for_app_registration_io > + * by a successful call to register or modify and pass it into > + * subsequent calls to modify or deregister. > + * > + * register_fd_hooks may be called only once for each libxl_ctx. > + * libxl may make calls to register/modify/deregister from within > + * any libxl function (indeed, it will usually call register from > + * register_event_hooks). Conversely, the application MUST NOT make > + * the event occurrence calls (libxl_osevent_occurred_*) into libxl > + * reentrantly from within libxl (for example, from within the > + * register/modify functions). > + * > + * Lock hierarchy: the register/modify/deregister functions may be > + * called with locks held. These locks (the "libxl internal locks") > + * are inside the libxl_ctx. Therefore, if those register functions > + * acquire any locks of their own ("caller register locks") outside > + * libxl, to avoid deadlock one of the following must hold for each > + * such caller register lock: > + * (a) "acquire libxl internal locks before caller register lock": > + * No libxl function may be called with the caller register > + * lock held. > + * (b) "acquire caller register lock before libxl internal locks": > + * No libxl function may be called _without_ the caller > + * register lock held. > + * Of these we would normally recommend (a). > + * > + * The value *hooks is not copied and must outlast the libxl_ctx. > + */while this description is very verbose, it doesn''t contain informations on: - what is void *user; - what is "const libxl_osevent_hooks *hooks", in particular the role of each of these function pointers and the description of their arguments. If I am a user of the library, how am I supposed to pass as user? and as hooks? I think these few lines should go first, then the description of the contract.> +/* It is NOT legal to call _occurred_ reentrantly within any libxl > + * function. Specifically it is NOT legal to call it from within > + * a register callback. Conversely, libxl MAY call register/deregister > + * from within libxl_event_registered_call_*. > + */ > + > +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl, > + int fd, short events, short revents); > + > +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl); > + /* Implicitly, on entry to this function the timeout has been > + * deregistered. If _occurred_timeout is called, libxl will not > + * call timeout_deregister; if it wants to requeue the timeout it > + * will call timeout_register again. > + */ > + > +#endif > + > +/* > + * Local variables: > + * mode: C > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h > index d015c7c..88e7dbb 100644 > --- a/tools/libxl/libxl_internal.h > +++ b/tools/libxl/libxl_internal.h > @@ -24,6 +24,9 @@ > #include <stdlib.h> > #include <string.h> > #include <pthread.h> > +#include <inttypes.h> > +#include <assert.h> > +#include <sys/poll.h> > > #include <xs.h> > #include <xenctrl.h> > @@ -91,6 +94,66 @@ _hidden void libxl__log(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, > > /* these functions preserve errno (saving and restoring) */ > > +typedef struct libxl__gc libxl__gc; > + > +typedef struct libxl__ev_fd libxl__ev_fd; > +typedef void libxl__ev_fd_callback(libxl__gc *gc, libxl__ev_fd *ev, > + int fd, short events, short revents); > +struct libxl__ev_fd { > + /* all private for libxl__ev_fd... */ > + LIBXL_LIST_ENTRY(libxl__ev_fd) entry; > + int fd; > + short events; > + int in_beforepolled; /* -1 means not in fd_beforepolled */ > + void *for_app_reg; > + libxl__ev_fd_callback *func; > +}; > + > + > +typedef struct libxl__ev_time libxl__ev_time; > +typedef void libxl__ev_time_callback(libxl__gc *gc, libxl__ev_time *ev, > + const struct timeval *requested_abs); > +struct libxl__ev_time { > + /* all private for libxl__ev_time... */ > + int infinite; /* not registered in list or with app if infinite */ > + LIBXL_TAILQ_ENTRY(libxl__ev_time) entry; > + struct timeval abs; > + void *for_app_reg; > + libxl__ev_time_callback *func; > +}; > + > +typedef struct libxl__ev_xswatch libxl__ev_xswatch; > +typedef void libxl__ev_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch*, > + const char *watch_path, const char *event_path); > +struct libxl__ev_xswatch { > + /* caller should include this in their own struct */ > + /* contents are private to xswatch_register */ > + int slotnum; > + uint32_t counterval; > + char *path; > + libxl__ev_xswatch_callback *callback; > +}; > + > +/* > + * An entry in the watch_slots table is either: > + * 1. an entry in the free list, ie NULL or pointer to next free list entry > + * 2. an pointer to a libxl__ev_xswatch > + * > + * But we don''t want to use unions or type-punning because the > + * compiler might "prove" that our code is wrong and misoptimise it. > + * > + * The rules say that all struct pointers have identical > + * representation and alignment requirements (C99+TC1+TC2 6.2.5p26) so > + * what we do is simply declare our array as containing only the free > + * list pointers, and explicitly convert from and to our actual > + * xswatch pointers when we store and retrieve them. > + */ > +typedef struct libxl__ev_watch_slot { > + LIBXL_SLIST_ENTRY(struct libxl__ev_watch_slot) empty; > +} libxl__ev_watch_slot; > + > +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum); > + > struct libxl__ctx { > xentoollog_logger *lg; > xc_interface *xch; > @@ -108,6 +171,23 @@ struct libxl__ctx { > * documented in the libxl public interface. > */ > > + int osevent_in_hook; > + const libxl_osevent_hooks *osevent_hooks; > + void *osevent_user; > + /* See the comment for OSEVENT_HOOK_INTERN in libxl_event.c > + * for restrictions on the use of the osevent fields. */ > + > + int fd_beforepolled_allocd, fd_beforepolled_used; > + libxl__ev_fd **fd_beforepolled; /* see libxl_osevent_beforepoll */ > + LIBXL_LIST_HEAD(, libxl__ev_fd) efds; > + LIBXL_TAILQ_HEAD(, libxl__ev_time) etimes; > + > + libxl__ev_watch_slot *watch_slots; > + int watch_nslots; > + LIBXL_SLIST_HEAD(, libxl__ev_watch_slot) watch_freeslots; > + uint32_t watch_counter; /* helps disambiguate slot reuse */ > + libxl__ev_fd watch_efd; > + > /* for callers who reap children willy-nilly; caller must only > * set this after libxl_init and before any other call - or > * may leave them untouched */ > @@ -138,12 +218,12 @@ typedef struct { > > #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y))) > > -typedef struct { > +struct libxl__gc { > /* mini-GC */ > int alloc_maxsize; > void **alloc_ptrs; > libxl_ctx *owner; > -} libxl__gc; > +}; > > #define LIBXL_INIT_GC(gc,ctx) do{ \ > (gc).alloc_maxsize = 0; \ > @@ -209,9 +289,137 @@ _hidden char *libxl__xs_read(libxl__gc *gc, xs_transaction_t t, > _hidden char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t, > const char *path, unsigned int *nb); > /* On error: returns NULL, sets errno (no logging) */ > - > _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid); > > + > +/* > + * Event generation functions provided by the libxl event core to the > + * rest of libxl. Implemented in terms of _beforepoll/_afterpoll > + * and/or the fd registration machinery, as provided by the > + * application. > + * > + * Semantics are similar to those of the fd and timeout registration > + * functions provided to libxl_osevent_register_hooks. > + * > + * Non-0 returns from libxl__ev_{modify,deregister} have already been > + * logged by the core and should be returned unmodified to libxl''s > + * caller; NB that they may be valid libxl error codes but they may > + * also be positive numbers supplied by the caller. > + * > + * In each case, there is a libxl__ev_FOO structure which can be in > + * one of three states: > + * > + * Undefined - Might contain anything. All-bits-zero is > + * an undefined state. > + * > + * Idle - Struct contents are defined enough to pass to any > + * libxl__ev_FOO function but not registered and > + * callback will not be called. The struct does not > + * contain references to any allocated resources so > + * can be thrown away. > + * > + * Active - Request for events has been registered and events > + * may be generated. _deregister must be called to > + * reclaim resources. > + * > + * These functions are provided for each kind of event KIND: > + * > + * int libxl__ev_KIND_register(libxl__gc *gc, libxl__ev_KIND *GEN, > + * libxl__ev_KIND_callback *FUNC, > + * DETAILS); > + * On entry *GEN must be in state Undefined or Idle. > + * Returns a libxl error code; on error return *GEN is Idle. > + * On successful return *GEN is Active and FUNC wil be > + * called by the event machinery in future. FUNC will > + * not be called from within the call to _register. > + * > + * void libxl__ev_KIND_deregister(libxl__gc *gc, libxl__ev_KIND *GEN_upd); > + * On entry *GEN must be in state Active or Idle. > + * On return it is Idle. (Idempotent.) > + * > + * void libxl__ev_KIND_init(libxl__ev_KIND *GEN); > + * Provided for initialising an Undefined KIND. > + * On entry *GEN must be in state Idle or Undefined. > + * On return it is Idle. (Idempotent.) > + * > + * int libxl__ev_KIND_isregistered(const libxl__ev_KIND *GEN); > + * On entry *GEN must be Idle or Active. > + * Returns nonzero if it is Active, zero otherwise. > + * Cannot fail. > + * > + * int libxl__ev_KiND_modify(libxl__gc*, libxl__ev_KIND *GEN, > + * DETAILS); > + * Only provided for some kinds of generator. > + * On entry *GEN must be Active and on return, whether successful > + * or not, it will be Active. > + * Returns a libxl error code; on error the modification > + * is not effective. > + * > + * All of these functions are fully threadsafe and may be called by > + * general code in libxl even from within event callback FUNCs. > + */ > + > + > +_hidden int libxl__ev_fd_register(libxl__gc*, libxl__ev_fd *ev_out, > + libxl__ev_fd_callback*, > + int fd, short events /* as for poll(2) */); > +_hidden int libxl__ev_fd_modify(libxl__gc*, libxl__ev_fd *ev, > + short events); > +_hidden void libxl__ev_fd_deregister(libxl__gc*, libxl__ev_fd *ev); > +static inline void libxl__ev_fd_init(libxl__ev_fd *efd) > + { efd->fd = -1; } > +static inline int libxl__ev_fd_isregistered(libxl__ev_fd *efd) > + { return efd->fd >= 0; } > + > +_hidden int libxl__ev_time_register_rel(libxl__gc*, libxl__ev_time *ev_out, > + libxl__ev_time_callback*, > + int milliseconds /* as for poll(2) */); > +_hidden int libxl__ev_time_register_abs(libxl__gc*, libxl__ev_time *ev_out, > + libxl__ev_time_callback*, > + struct timeval); > +_hidden int libxl__ev_time_modify_rel(libxl__gc*, libxl__ev_time *ev, > + int milliseconds /* as for poll(2) */); > +_hidden int libxl__ev_time_modify_abs(libxl__gc*, libxl__ev_time *ev, > + struct timeval); > +_hidden void libxl__ev_time_deregister(libxl__gc*, libxl__ev_time *ev); > +static inline void libxl__ev_time_init(libxl__ev_time *ev) > + { ev->func = 0; } > +static inline int libxl__ev_time_isregistered(libxl__ev_time *ev) > + { return !!ev->func; } > + > + > +_hidden int libxl__ev_xswatch_register(libxl__gc*, libxl__ev_xswatch *xsw_out, > + libxl__ev_xswatch_callback*, > + const char *path /* copied */); > +_hidden void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch*); > + > +static inline void libxl__ev_xswatch_init(libxl__ev_xswatch *xswatch_out) > + { xswatch_out->slotnum = -1; } > +static inline int libxl__ev_xswatch_isregistered(const libxl__ev_xswatch *xw) > + { return xw->slotnum >= 0; } > + > + > + > +_hidden void libxl__event_disaster(libxl__gc*, const char *msg, int errnoval, > + libxl_event_type type /* may be 0 */, > + const char *file, int line, > + const char *func); > + /* > + * In general, call this via the macro LIBXL__EVENT_DISASTER. > + * > + * Event-generating functions may call this if they might have > + * wanted to generate an event (either an internal one ie a > + * libxl__ev_FOO_callback or an application event), but are > + * prevented from doing so due to eg lack of memory. > + * > + * NB that this function may return and the caller isn''t supposed to > + * then crash, although it may fail (and henceforth leave things in > + * a state where many or all calls fail). > + */ > +#define LIBXL__EVENT_DISASTER(gc, msg, errnoval, type) \ > + libxl__event_disaster(gc, msg, errnoval, type, __FILE__, __LINE__, __func__)any reason why this shouldn''t be a static inline?> + > /* from xl_dom */ > _hidden libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid); > _hidden int libxl__domain_shutdown_reason(libxl__gc *gc, uint32_t domid); > @@ -536,6 +744,8 @@ _hidden int libxl__parse_mac(const char *s, libxl_mac mac); > /* compare mac address @a and @b. 0 if the same, -ve if a<b and +ve if a>b */ > _hidden int libxl__compare_macs(libxl_mac *a, libxl_mac *b); > > +_hidden int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r); > + > #define STRINGIFY(x) #x > #define TOSTRING(x) STRINGIFY(x) > > -- > 1.7.2.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel >
Ian Jackson
2011-Dec-09 16:19 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Firstly, Stefano, please trim your quotes. You don''t need to quote the whole zillion-line patch. Just quote the bits that are relevant. Otherwise people may miss your comments as they page through trying to find them. Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> On Mon, 5 Dec 2011, Ian Jackson wrote: > > +#define OSEVENT_HOOK_INTERN(defval, hookname, ...) \ > > + (CTX->osevent_hooks \ > > + ? (CTX->osevent_in_hook++, \ > > + CTX->osevent_hooks->hookname(CTX->osevent_user, __VA_ARGS__), \ > > + CTX->osevent_in_hook--) \ > > + : defval) > > + > > +#define OSEVENT_HOOK(hookname,...) \ > > + OSEVENT_HOOK_INTERN(0, hookname, __VA_ARGS__) > > + > > +#define OSEVENT_HOOK_VOID(hookname,...) \ > > + OSEVENT_HOOK_INTERN((void)0, hookname, __VA_ARGS__) > > Is there any reasons why we cannot use static inline functions here?Yes, I''m afraid so. The types of the hooks vary, and even if it weren''t for that, C doesn''t have Lisp''s "apply".> > + for (i=CTX->watch_nslots; i<newarraysize; i++) > > does not follow the CODING_STYLE, it should be > > for (i = CTX->watch_nslots; i < newarraysize; i++)Fixed, thanks.> > + LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, > > + &newarray[i], empty); > > + CTX->watch_slots = newarray; > > + CTX->watch_nslots = newarraysize; > > + } > > would it make sense to move this code in its own allocate_watch_slots > function? > > > +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > > + struct pollfd *fds, int *timeout_upd, > > + struct timeval now); > > + /* The caller should provide beforepoll with some space for libxl''s > > + * fds, and tell libxl how much space is available by setting *nfds_io.... [ many lines of commentary ]> > + * libxl_osevent_beforepoll will only reduce the timeout, naturally. > > + */ > > so far we have always added the comment on a function above the > declaration of the function; we should keep doing it for consistencyI disagree. That comment style involves either: 1. Repeating the declaration at the top of the comment (or worse, repeating the information in the declaration but in a different format, doxygen-style); or 2. Writing a comment which contains almost entirely forward references This is not too bad if the comment is a one-liner. But with a big comment like this, you end up with something like: /* The caller should provide beforepoll with some space for libxl''s * fds, and tell libxl how much space is available by setting *nfds_io. * fds points to the start of this space (and fds may be a pointer into * a larger array, for example, if the application has some fds of * its own that it is interested in). * * On return *nfds_io will in any case have been updated by libxl * according to how many fds libxl wants to poll on. * * If the space was sufficient, libxl fills in fds[0..<new * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed, * and returns ok. * * If space was insufficient, fds[0..<old *nfds_io>] is undefined on * return; *nfds_io on return will be greater than the value on * entry; *timeout_upd may or may not have been updated; and * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this case * the application needs to make more space (enough space for * *nfds_io struct pollfd) and then call beforepoll again, before * entering poll(2). Typically this will involve calling realloc. * * The application may call beforepoll with fds==NULL and * *nfds_io==0 in order to find out how much space is needed. * * *timeout_upd is as for poll(2): it''s in milliseconds, and * negative values mean no timeout (infinity). * libxl_osevent_beforepoll will only reduce the timeout, naturally. */ int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, struct pollfd *fds, int *timeout_upd, struct timeval now); This is very disjointed if you try to read it. You start with /* The caller should provide beforepoll with some space for libxl''s * fds, and tell libxl how much space is available by setting *nfds_io. * fds points to the start of this space (and fds may be a pointer into * a larger array, for example, if the application has some fds of * its own that it is interested in). and the natural reaction is "What caller?? What is this beforepoll and *nfds_io of which you speak?? What on earth are we talking about??" The alternative, repeating the declaration, violates the principle that things should be said (and defined) in the code if that''s possible, rather than having the primary reference be a comment. It also violates the principle of trying to avoid putting the same information in two places. If you want consistency then we should change the coding style to put comment about a function or object declaration after the prototype or declaration.> > +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds, > > + struct timeval now); > > + /* nfds and fds[0..nfds] must be from the most recent call to > > + * _beforepoll, as modified by poll. > > + * > > + * This function actually performs all of the IO and other actions, > > + * and generates events (libxl_event), which are implied by either > > + * (a) the time of day or (b) both (i) the returned information from > > + * _beforepoll, and (ii) the results from poll specified in > > + * fds[0..nfds-1]. Generated events can then be retrieved by > > + * libxl_event_check. > > + */ > > + > > I see that the implementation of libxl_event_check is actually missing > from this patch. > Is this patch supposed to compiled, even without the actual libxl_event > generation? Or are the two patches have to be committed together?libxl_event_check is not referred to by the code in this patch. It is introduced in 15/15. The comment is indeed not 100% true in this patch but it seemed better to provide here a comment explaining how things are going to be rather than writing * This function performs all of the IO and other actions, * but this does not currently have any visible effect outside * libxl. in this patch and removing it in the next one. My series compiles, and indeed is supposed to work, after each patch.> > +typedef struct libxl_osevent_hooks { > > + int (*fd_register)(void *uselibxl_event_check.r, int fd, void **for_app_registration_out, > > + short events, void *for_libxl); > > + int (*fd_modify)(void *user, int fd, void **for_app_registration_update, > > + short events); > > + void (*fd_deregister)(void *user, int fd, void *for_app_registration); > > + int (*timeout_register)(void *user, void **for_app_registration_out, > > + struct timeval abs, void *for_libxl); > > + int (*timeout_modify)(void *user, void **for_app_registration_update, > > + struct timeval abs); > > + void (*timeout_deregister)(void *user, void *for_app_registration_io); > > +} libxl_osevent_hooks; > > + > > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > > + const libxl_osevent_hooks *hooks, > > + void *user);...> while this description is very verbose, it doesn''t contain informations > on: > > - what is void *user;I would have thought this was obvious. Every situation in C where a function pointer is passed needs also to pass a void* (or the equivalent) so that some context or dynamic information from the original caller can be passed to the inner called function. So user is stored by libxl and passed to the hooks.> - what is "const libxl_osevent_hooks *hooks", in particular the role of > each of these function pointers and the description of their > arguments.The role of these function pointers is this:> > + /* The application which calls register_fd_hooks promises to > > + * maintain a register of fds and timeouts that libxl is interested > > + * in, and make calls into libxl (libxl_osevent_occurred_*) > > + * when those fd events and timeouts occur. This is more efficient > > + * than _beforepoll/_afterpoll if there are many fds (which can > > + * happen if the same libxl application is managing many domains).Ie, this is how libxl tells the application what fds and timeouts libxl is interested in.> If I am a user of the library, how am I supposed to pass as user? and as > hooks? > I think these few lines should go first, then the description of the > contract.Did you spot this comment, earlier ?> > + * There are two approaches available. The first is appropriate for > > + * simple programs handling reasonably small numbers of domains: > > + *...> > + * The second approach uses libxl_osevent_register_hooks and is > > + * suitable for programs which are already using a callback-based > > + * event library.libxl_osevent_hooks is for this second approach. If you know what a callback-based event library is - particularly if you actually have one in front of you - all of this should be obvious. If you don''t know what a callback-based event library is, then you don''t have one and you don''t want to use this interface. To help make it clear to you, here is an example of a callback-based event library: http://www.chiark.greenend.org.uk/doc/liboop-doc/html/ref.html http://www.chiark.greenend.org.uk/doc/liboop-doc/html/ (Copy of the docs as installed on my colo as apparently the upstream website has gone away.)> > +#define LIBXL__EVENT_DISASTER(gc, msg, errnoval, type) \ > > + libxl__event_disaster(gc, msg, errnoval, type, __FILE__, __LINE__, __func__) > > any reason why this shouldn''t be a static inline?__FILE__, __LINE__, __func__ Ian.
Ian Campbell
2011-Dec-09 16:27 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Fri, 2011-12-09 at 15:44 +0000, Stefano Stabellini wrote: [...]> > tools/libxl/Makefile | 2 +- > > tools/libxl/libxl.c | 25 ++ > > tools/libxl/libxl.h | 6 + > > tools/libxl/libxl_event.c | 711 ++++++++++++++++++++++++++++++++++++++++++ > > tools/libxl/libxl_event.h | 199 ++++++++++++ > > tools/libxl/libxl_internal.h | 216 +++++++++++++-Please do trim the thousand lines of patch which you aren''t commenting on. Just including the hunk or function you are commenting on is sufficient for context and snipping appropriately makes makes it far easier to find the wheat in the chafe. (this applies to everyone, this is just the latest one to annoy me ;-)) Ian. [...snip...]
Ian Jackson
2011-Dec-09 16:51 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Ian Campbell writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> On Thu, 2011-12-08 at 19:53 +0000, Ian Jackson wrote: > > All the existing files in libxl/ mention this nonexistent file > > LICENCE. I think we should fix this in a separate patch. I''d argue > > that my copying of the existing text isn''t making the situation worse. > > Sure, I didn''t mean to suggest you needed to fix this in this series, I > just happened to observe it here.Right. Yes.> > > > +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev, > > > > + libxl__ev_fd_callback *func, > > > > + int fd, short events) { > > > > > > Strictly speaking CODING_STYLE requires the { to be on the next line. > > > > Oh, I probably have a lot of those. Damn. > > Yeah, I refrained from commenting every time ;-)Fixed.> > You mean "int xs_path_is_subpath_p(const char *parent, const char *child)" ?...> Wouldn''t most users of libxenstore doing watches need something like > this (and probably either open code it or erroneously omit it)?Many. If you are careful enough with your tokens you might not need to.> Regardless of where it goes moving that logic into a helper function > will make it clearer what is going on, both by having a descriptive name > and allowing the logic to be a bit more spaced out / commented, the last > clause in particular is slightly subtle.OK, I have split this out into a function in libxenstore (in a separate patch): /* Returns true if child is either equal to parent, or a node underneath * parent; or false otherwise. Done by string comparison, so relative and * absolute pathnames never in a parent/child relationship by this * definition. Cannot fail. */ bool xs_path_is_subpath(const char *parent, const char *child); You''re right, the resulting code is clearer I think. Ian.
Stefano Stabellini
2011-Dec-09 16:57 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Fri, 9 Dec 2011, Ian Jackson wrote:> Firstly, Stefano, please trim your quotes. You don''t need to quote > the whole zillion-line patch. Just quote the bits that are relevant. > Otherwise people may miss your comments as they page through trying to > find them.I personally prefer to keep the full quote so that I can search for references without having to go back to the other email. However I do understand that some people don''t like this so I''ll trim my comment to your patches in the future.> > > +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > > > + struct pollfd *fds, int *timeout_upd, > > > + struct timeval now); > > > + /* The caller should provide beforepoll with some space for libxl''s > > > + * fds, and tell libxl how much space is available by setting *nfds_io. > ... [ many lines of commentary ] > > > + * libxl_osevent_beforepoll will only reduce the timeout, naturally. > > > + */ > > > > so far we have always added the comment on a function above the > > declaration of the function; we should keep doing it for consistency > > I disagree. That comment style involves either: > > 1. Repeating the declaration at the top of the comment (or worse, > repeating the information in the declaration but in a different > format, doxygen-style); or > > 2. Writing a comment which contains almost entirely forward references > > This is not too bad if the comment is a one-liner. But with a big > comment like this, you end up with something like: > > /* The caller should provide beforepoll with some space for libxl''s > * fds, and tell libxl how much space is available by setting *nfds_io. > * fds points to the start of this space (and fds may be a pointer into > * a larger array, for example, if the application has some fds of > * its own that it is interested in). > * > * On return *nfds_io will in any case have been updated by libxl > * according to how many fds libxl wants to poll on. > * > * If the space was sufficient, libxl fills in fds[0..<new > * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed, > * and returns ok. > * > * If space was insufficient, fds[0..<old *nfds_io>] is undefined on > * return; *nfds_io on return will be greater than the value on > * entry; *timeout_upd may or may not have been updated; and > * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this case > * the application needs to make more space (enough space for > * *nfds_io struct pollfd) and then call beforepoll again, before > * entering poll(2). Typically this will involve calling realloc. > * > * The application may call beforepoll with fds==NULL and > * *nfds_io==0 in order to find out how much space is needed. > * > * *timeout_upd is as for poll(2): it''s in milliseconds, and > * negative values mean no timeout (infinity). > * libxl_osevent_beforepoll will only reduce the timeout, naturally. > */ > int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io, > struct pollfd *fds, int *timeout_upd, > struct timeval now); > > This is very disjointed if you try to read it. You start with > > /* The caller should provide beforepoll with some space for libxl''s > * fds, and tell libxl how much space is available by setting *nfds_io. > * fds points to the start of this space (and fds may be a pointer into > * a larger array, for example, if the application has some fds of > * its own that it is interested in). > > and the natural reaction is "What caller?? What is this beforepoll and > *nfds_io of which you speak?? What on earth are we talking about??" > > The alternative, repeating the declaration, violates the principle > that things should be said (and defined) in the code if that''s > possible, rather than having the primary reference be a comment. It > also violates the principle of trying to avoid putting the same > information in two places.I would prefer having a brief explanation of what the parameters are before the function. At least a few times this what my eyes where looking for reading this patch. See for example arch/x86/include/asm/paravirt_types.h in the linux kernel: the long description of the MACROs is before the MACROs.> If you want consistency then we should change the coding style to put > comment about a function or object declaration after the prototype or > declaration.I disagree.> > I see that the implementation of libxl_event_check is actually missing > > from this patch. > > Is this patch supposed to compiled, even without the actual libxl_event > > generation? Or are the two patches have to be committed together? > > libxl_event_check is not referred to by the code in this patch. It is > introduced in 15/15. The comment is indeed not 100% true in this > patch but it seemed better to provide here a comment explaining how > things are going to be rather than writing > > * This function performs all of the IO and other actions, > * but this does not currently have any visible effect outside > * libxl. > > in this patch and removing it in the next one. > > My series compiles, and indeed is supposed to work, after each patch.Yes, I think it is better this way.> > > +typedef struct libxl_osevent_hooks { > > > + int (*fd_register)(void *uselibxl_event_check.r, int fd, void **for_app_registration_out, > > > + short events, void *for_libxl); > > > + int (*fd_modify)(void *user, int fd, void **for_app_registration_update, > > > + short events); > > > + void (*fd_deregister)(void *user, int fd, void *for_app_registration); > > > + int (*timeout_register)(void *user, void **for_app_registration_out, > > > + struct timeval abs, void *for_libxl); > > > + int (*timeout_modify)(void *user, void **for_app_registration_update, > > > + struct timeval abs); > > > + void (*timeout_deregister)(void *user, void *for_app_registration_io); > > > +} libxl_osevent_hooks; > > > + > > > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > > > + const libxl_osevent_hooks *hooks, > > > + void *user); > ... > > while this description is very verbose, it doesn''t contain informations > > on: > > > > - what is void *user; > > I would have thought this was obvious. Every situation in C where a > function pointer is passed needs also to pass a void* (or the > equivalent) so that some context or dynamic information from the > original caller can be passed to the inner called function. So user > is stored by libxl and passed to the hooks.It might be obvious but it is not written anywhere. Considering the level of details you went through in the following paragraph, I am surprised that you left to guessing what this parameter is for. Better be pedantic than leaving things to imagination.> > - what is "const libxl_osevent_hooks *hooks", in particular the role of > > each of these function pointers and the description of their > > arguments. > > The role of these function pointers is this: > > > > + /* The application which calls register_fd_hooks promises to > > > + * maintain a register of fds and timeouts that libxl is interested > > > + * in, and make calls into libxl (libxl_osevent_occurred_*) > > > + * when those fd events and timeouts occur. This is more efficient > > > + * than _beforepoll/_afterpoll if there are many fds (which can > > > + * happen if the same libxl application is managing many domains). > > Ie, this is how libxl tells the application what fds and timeouts > libxl is interested in. > > > If I am a user of the library, how am I supposed to pass as user? and as > > hooks? > > I think these few lines should go first, then the description of the > > contract. > > Did you spot this comment, earlier ?That comment explains what the application promises, not what the parameters are. However I know what you mean: from that paragraph and from the name of the parameters it is easy to guess what they are for. Still I would rather avoid leaving anything to guessing.> > > + * The second approach uses libxl_osevent_register_hooks and is > > > + * suitable for programs which are already using a callback-based > > > + * event library. > > libxl_osevent_hooks is for this second approach. If you know what a > callback-based event library is - particularly if you actually have > one in front of you - all of this should be obvious. If you don''t > know what a callback-based event library is, then you don''t have one > and you don''t want to use this interface.I disagree. Even if it is the first time one sees a callback-based event library, one should be able to use it without trouble. If it is too difficult, maybe it is not designed in the best possible way.
Ian Jackson
2011-Dec-09 17:00 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> On Fri, 9 Dec 2011, Ian Jackson wrote: > > Firstly, Stefano, please trim your quotes. You don''t need to quote > > the whole zillion-line patch. Just quote the bits that are relevant. > > Otherwise people may miss your comments as they page through trying to > > find them. > > I personally prefer to keep the full quote so that I can search for > references without having to go back to the other email. However I do > understand that some people don''t like this so I''ll trim my comment to > your patches in the future.Everyone on the list needs to be able to read these review comments, not just the author of the original patch. I see Ian C agrees with me. The standard approach should always be to trim the patch to the relevant parts only. Thanks, Ian.
Ian Campbell
2011-Dec-09 17:07 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Fri, 2011-12-09 at 16:57 +0000, Stefano Stabellini wrote:> On Fri, 9 Dec 2011, Ian Jackson wrote: > > Firstly, Stefano, please trim your quotes. You don''t need to quote > > the whole zillion-line patch. Just quote the bits that are relevant. > > Otherwise people may miss your comments as they page through trying to > > find them. > > I personally prefer to keep the full quote so that I can search for > references without having to go back to the other email.A proper mailer has at least two windows. (/duck and cover) ;-) Ian.
Ian Jackson
2011-Dec-09 17:17 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> On Fri, 9 Dec 2011, Ian Jackson wrote: > > The alternative, repeating the declaration, violates the principle > > that things should be said (and defined) in the code if that''s > > possible, rather than having the primary reference be a comment. It > > also violates the principle of trying to avoid putting the same > > information in two places. > > I would prefer having a brief explanation of what the parameters are > before the function. At least a few times this what my eyes where > looking for reading this patch.The parameters are listed in the function prototype! That''s what the function prototype is! The very first thing you should be reading is the function prototype. If by "what they are" you mean you want to know what they mean, then that is why we give them names rather than just using anonymous parameters. Or are you saying that you want something like this: int (*fd_register)(void *user, int fd, void **for_app_registration_out, short events, void *for_libxl); /* @fd@ the file descriptor ... This is pointless boilerplate. Obviously "int fd" is a file descriptor and it doesn''t help to write it out in English as well as C. This style also encourages formulaic descriptions like this: * @reg@ application''s registration token (out parameter)> See for example arch/x86/include/asm/paravirt_types.h in the linux > kernel: the long description of the MACROs is before the MACROs.Macros are different because they don''t have prototypes, just definitions. Nontrivial macros often need a comment beforehand to serve in place of the function prototype. You''ll see that in general my macros have the comment beforehand, for example: /* * Inserts "elm_new" into the sorted list "head". * * "elm_search" must be a loop search variable of the same type as * "elm_new". "new_after_search_p" must be an expression which is * true iff the element "elm_new" sorts after the element * "elm_search". * * "search_body" can be empty, or some declaration(s) and statement(s) * needed for "new_after_search_p". */ #define LIBXL_TAILQ_INSERT_SORTED(head, entry, elm_new, elm_search, \ search_body, new_after_search_p) \ do { \> > > > +typedef struct libxl_osevent_hooks { > > > > + int (*fd_register)(void *uselibxl_event_check.r, int fd, void **for_app_registration_out, > > > > + short events, void *for_libxl); > > > > + int (*fd_modify)(void *user, int fd, void **for_app_registration_update, > > > > + short events); > > > > + void (*fd_deregister)(void *user, int fd, void *for_app_registration); > > > > + int (*timeout_register)(void *user, void **for_app_registration_out, > > > > + struct timeval abs, void *for_libxl); > > > > + int (*timeout_modify)(void *user, void **for_app_registration_update, > > > > + struct timeval abs); > > > > + void (*timeout_deregister)(void *user, void *for_app_registration_io); > > > > +} libxl_osevent_hooks; > > > > + > > > > +void libxl_osevent_register_hooks(libxl_ctx *ctx, > > > > + const libxl_osevent_hooks *hooks, > > > > + void *user); > > ... > > > while this description is very verbose, it doesn''t contain informations > > > on: > > > > > > - what is void *user; > > > > I would have thought this was obvious. Every situation in C where a > > function pointer is passed needs also to pass a void* (or the > > equivalent) so that some context or dynamic information from the > > original caller can be passed to the inner called function. So user > > is stored by libxl and passed to the hooks. > > It might be obvious but it is not written anywhere. Considering the > level of details you went through in the following paragraph, I am > surprised that you left to guessing what this parameter is for. Better > be pedantic than leaving things to imagination.All of the details in that paragraph are there because they not otherwise clear. In particular, there are many semantic details which need to be covered. It''s precisely because there are so many important details to state, that it''s not helpful to restate in sentences in comments things which have already been stated in the choice of function and parameter names. But I can add a sentence about "user" if that would help: * * The value of user is stored by libxl and passed to the callbacks. Would that address this objection ? I definitely don''t want to add a sentence next to "timeout_register" saying "this is for libxl to register a timeout" and another sentence saying that the "struct timeval abs" is the absolute time at which the timeout should fire and another sentence saying that "int fd" is the file descriptor and on on. Ian.
Stefano Stabellini
2011-Dec-09 18:12 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Fri, 9 Dec 2011, Ian Jackson wrote:> All of the details in that paragraph are there because they not > otherwise clear. In particular, there are many semantic details which > need to be covered. It''s precisely because there are so many > important details to state, that it''s not helpful to restate in > sentences in comments things which have already been stated in the > choice of function and parameter names. > > But I can add a sentence about "user" if that would help: > > * > * The value of user is stored by libxl and passed to the callbacks. > > Would that address this objection ?Yes, that would help. Maybe something similar for the parameters of the functions in libxl_osevent_hooks, in particular for_app_registration_update.
Stefano Stabellini
2011-Dec-09 18:14 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Mon, 5 Dec 2011, Ian Jackson wrote:> +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid, > + libxl_ev_user user, libxl_evgen_domain_death **evgen_out) { > + GC_INIT(ctx); > + libxl_evgen_domain_death *evg, *evg_search; > + int rc; > + > + CTX_LOCK; > + > + evg = malloc(sizeof(*evg)); if (!evg) { rc = ERROR_NOMEM; goto out; } > + memset(evg, 0, sizeof(*evg)); > + evg->domid = domid; > + evg->user = user; > + > + LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, ,is this a mistake? ^> +void libxl__event_occurred(libxl__gc *gc, libxl_event *event) { > + if (CTX->event_hooks && > + (CTX->event_hooks->event_occurs_mask & (1UL << event->type))) { > + /* libxl__free_all will call the callback, just before exit > + * from libxl.Please extend this comment: "just before leaving libxl to go back to the caller". Also, even though libxl__free_all might be the right place to call the callbacks, the name of the function (libxl__free_all) won''t completely reflect its behaviour anymore. Maybe we need to rename libxl__free_all?> +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, > + unsigned long typemask, > + libxl_event_predicate *pred, void *pred_user) { > + GC_INIT(ctx); > + CTX_LOCK; > + int rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); > + CTX_UNLOCK; > + GC_FREE; > + return rc; > +}I think it is confusing to call event_check_*unlocked* from within CTX_LOCK/CTX_UNLOCK.
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> On Mon, 5 Dec 2011, Ian Jackson wrote: > > + LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, , > > is this a mistake? ^No. It''s a parameter to allow the macro''s caller to introduce variable declarations and arbitrary code into the search loop, for the benefit of their predicate. We don''t need it here. I''ve added /*empty*/ in the empty parameter to avoid people tripping over it.> > +void libxl__event_occurred(libxl__gc *gc, libxl_event *event) { > > + if (CTX->event_hooks && > > + (CTX->event_hooks->event_occurs_mask & (1UL << event->type))) { > > + /* libxl__free_all will call the callback, just before exit > > + * from libxl. > > Please extend this comment: "just before leaving libxl to go back to the > caller". Also, even though libxl__free_all might be the right place to > call the callbacks, the name of the function (libxl__free_all) won''t > completely reflect its behaviour anymore. Maybe we need to rename > libxl__free_all?Yes, I think you''re probably right. I''ll add a patch to rename it to libxl__gc_cleanup, which I think is the best name I can think of for the moment.> > +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, > > + unsigned long typemask, > > + libxl_event_predicate *pred, void *pred_user) { > > + GC_INIT(ctx); > > + CTX_LOCK; > > + int rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user); > > + CTX_UNLOCK; > > + GC_FREE; > > + return rc; > > +} > > I think it is confusing to call event_check_*unlocked* from within > CTX_LOCK/CTX_UNLOCK.I''m open to other suggestions for the name of these functions, but I got the naming pattern from stdio. From man getc_unlocked(3) on squeeze: UNLOCKED_STDIO(3) Linux Programmer''s Manual UNLOCKED_STDIO(3) ... int getc_unlocked(FILE *stream); int getchar_unlocked(void); int putc_unlocked(int c, FILE *stream); ... DESCRIPTION Each of these functions has the same behavior as its counterpart with- out the "_unlocked" suffix, except that they do not use locking (they do not set locks themselves, and do not test for the presence of locks set by others) and hence are thread-unsafe. See flockfile(3). Now Linux and Xen have a tendency, when they need a name for an unlocked version of foo, to use the name _foo. Obviously this is no good in a userspace program and anyway I think it is a completely ridiculous convention. We need something much clearer. foo_internal is a possibility but that merely suggests that the GC_INIT has been done, and doesn''t make it 100% clear that the caller must already have done CTX_LOCK. Thanks, Ian.
On Fri, 2011-12-09 at 18:48 +0000, Ian Jackson wrote:> Now Linux and Xen have a tendency, when they need a name for an > unlocked version of foo, to use the name _foo. Obviously this is no > good in a userspace program and anyway I think it is a completely > ridiculous convention. We need something much clearer. > > foo_internal is a possibility but that merely suggests that the > GC_INIT has been done, and doesn''t make it 100% clear that the caller > must already have done CTX_LOCK.Some places also use foo_raw, not sure how much of an improvement that is though. Maybe a simple comment is sufficient: /* Must be called with $LOCK held */ int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r, ... It''s a shame there is no pthread_mutex_is_locked or an assert containing it would be nicely self documenting. I suppose CTX_LOCK could set a flag in the context which we could assert on, but, ick. Stepping back a bit: Since the lock is recursive do we really need the unlocked version? All the callers of event_check_unlocked (apart from libxl_event_check) could call libxl_event_check instead. Ian.
Ian Campbell writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> Stepping back a bit: Since the lock is recursive do we really need the > unlocked version? All the callers of event_check_unlocked (apart from > libxl_event_check) could call libxl_event_check instead.Well, we have to have an internal version because we don''t want to call GC_INIT again, obviously. Since the callers all take the lock the internal version doesn''t have to. It would be possible to have these functions pointlessly reacquire the lock, I guess, and rename it to "beforepoll_internal" etc. Ian.
On Mon, 2011-12-12 at 11:40 +0000, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"): > > Stepping back a bit: Since the lock is recursive do we really need the > > unlocked version? All the callers of event_check_unlocked (apart from > > libxl_event_check) could call libxl_event_check instead. > > Well, we have to have an internal version because we don''t want to > call GC_INIT again, obviously.In this case it would take a ctx not a gc and it''s ok and expected for libxl a function calling another libxl function to end up with another gc in the inner function (it happens all the time).> Since the callers all take the lock the internal version doesn''t have to. > > It would be possible to have these functions pointlessly reacquire the > lock, I guess, and rename it to "beforepoll_internal" etc.My point was that the "unlocked" version of the function makes naming the function confusing (or at least has led to some degree of bikeshedding) and that there is nothing wrong with pointlessly taking a recursive lock twice so we could avoid the issue by just having the external version and using it internally as well. IOW if you make beforepoll_internal take the lock as you suggest then you may as well inline it into libxl_osevent_beforepoll (removing the second lock use) and use that internally too. Ian.
Ian Campbell writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> On Mon, 2011-12-12 at 11:40 +0000, Ian Jackson wrote: > > Well, we have to have an internal version because we don''t want to > > call GC_INIT again, obviously. > > In this case it would take a ctx not a gc and it''s ok and expected for > libxl a function calling another libxl function to end up with another > gc in the inner function (it happens all the time).This is not allowed in functions which might generate events (ie, which might call libxl__event_occurred), because the application''s event callback will be called at an unexpected point in libxl''s execution. This has three problems: * There is a reentrancy hazard. Exactly whether this is a problem in a specific case is difficult to analyse; hence the recording of pending callbacks in the gc, so that they can be delayed until the gc is freed. * The application''s callbacks will be called with the libxl ctx locked. This might result in deadlock. * The application''s callbacks might be called in the wrong order because the inner gc (containing later events) is unwound before the outer gc (containing earlier events). In general this means that functions which lock the ctx must not allocate an inner gc.> IOW if you make beforepoll_internal take the lock as you suggest then > you may as well inline it into libxl_osevent_beforepoll (removing the > second lock use) and use that internally too.beforepoll_unlocked is called in two places: libxl_osevent_beforepoll, and libxl_event_wait. Ian.
On Mon, 2011-12-12 at 12:30 +0000, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"): > > On Mon, 2011-12-12 at 11:40 +0000, Ian Jackson wrote: > > > Well, we have to have an internal version because we don''t want to > > > call GC_INIT again, obviously. > > > > In this case it would take a ctx not a gc and it''s ok and expected for > > libxl a function calling another libxl function to end up with another > > gc in the inner function (it happens all the time). > > This is not allowed in functions which might generate events (ie, > which might call libxl__event_occurred), because the application''s > event callback will be called at an unexpected point in libxl''s > execution. This has three problems: > > * There is a reentrancy hazard. Exactly whether this is a problem in > a specific case is difficult to analyse; hence the recording of > pending callbacks in the gc, so that they can be delayed until the > gc is freed. > > * The application''s callbacks will be called with the libxl ctx > locked. This might result in deadlock. > > * The application''s callbacks might be called in the wrong order > because the inner gc (containing later events) is unwound before > the outer gc (containing earlier events). > > In general this means that functions which lock the ctx must not > allocate an inner gc.Hmm, yes that all makes sense :-/ I was a little surprised when I looked when writing my previous reply that LIBXL_INITGC doesn''t actually take nesting into account. I had expected that LIBXL_INITGC would return (or somehow chain) the existing GC when libxl is calling itself such that all the freeing work (and now callbacks) would only happen when exiting the final frame. It''s probably not so important for memory allocation cleanup but it would be a semantically useful change for the callbacks if we could arrange for them to happen only on final exit of the library -- exactly because of the difficulty of reasoning about things otherwise. Alas I can''t think of a good way to do this since the ctx can be shared, thread local storage would be one or libxl__gc_owner could return a special "nested ctx" instead of the real outer ctx, but, ick. If we can''t figure a way round this then the restriction about libxl not calling into itself via its own public interfaces should be documented (apologies if I''ve simply missed that bit, I did go and look because I thought I recalled seeing it, but I didn''t find it, I think I was thinking about the comment associated with the CTX lock). In particular if the restriction is that you cannot call public API functions which might generate events from within libxl then those functions need to be clearly annotated as potentially generating events.> > IOW if you make beforepoll_internal take the lock as you suggest then > > you may as well inline it into libxl_osevent_beforepoll (removing the > > second lock use) and use that internally too. > > beforepoll_unlocked is called in two places: libxl_osevent_beforepoll, > and libxl_event_wait.My suggestion was to call libxl_osevent_beforepoll from libxl_event_wait. The documentation for libxl_event_wait even says this is how libxl_event_wait is implemented (I know I''m not a liberty to take that as literally as that). Of course your explanation above put paid to that idea, unless we can work around it. Ian.
Ian Campbell
2011-Dec-12 14:17 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
On Fri, 2011-12-09 at 17:17 +0000, Ian Jackson wrote:> I definitely don''t want to add a sentence next to "timeout_register" > saying "this is for libxl to register a timeout" and another sentence > saying that the "struct timeval abs" is the absolute time at which the > timeout should fire and another sentence saying that "int fd" is the > file descriptor and on on.I agree that we don''t want/need this style of documentation. WRT comment placement I don''t feel especially strongly (so I''m no doubt going to regret getting involved) but the comment-after-prototype form does look odd to me. Putting the comment first is the norm (at least in the projects I follow), even those that don''t fall into the poor/boilerplate style documentation traps you describe (which we do have some of :-(). I think people are just used to reading the prototype and then looking for the comment above it, no matter how unnatural/inefficient/illogical that might seem. One specific pitfall which trips me up is that when one has multiple commented function prototypes in a block, thus: a_function(...) /* describe function a... * ... * at length */ b_function(...) /* describe function b... * ... * at length */ then figuring out which comment goes with which prototype is non-obvious and since I naturally look above the prototype for the comment I inevitably get the wrong one. This is compounded somewhat because we tend to document other types of object above rather than below and function prototypes are therefore something of a special case. (admittedly the correct solution here is more line breaks whatever the style of commenting used) We seem to have a mixture of both styles in libxl headers which is obviously much worse than either option. If an opinion is needed to tip the scales then I lean slightly towards commenting above but not noticeably changing the style of commentary. Ian.
Ian Jackson
2011-Dec-12 14:39 UTC
Re: [PATCH 14/15] libxl: New API for providing OS events to libxl
Ian Campbell writes ("Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl"):> One specific pitfall which trips me up is that when one has multiple > commented function prototypes in a block, thus: > > a_function(...) > /* describe function a... > * ... > * at length > */ > b_function(...) > /* describe function b... > * ... > * at length > */ > then figuring out which comment goes with which prototype is non-obviousI find these very confusing. There should be blank lines, like this: a_function(...) /* describe function a... * ... * at length */ b_function(...) /* describe function b... * ... * at length */> and since I naturally look above the prototype for the comment I > inevitably get the wrong one. This is compounded somewhat because we > tend to document other types of object above rather than below and > function prototypes are therefore something of a special case. > (admittedly the correct solution here is more line breaks whatever the > style of commenting used)Yes :-).> We seem to have a mixture of both styles in libxl headers which is > obviously much worse than either option. If an opinion is needed to tip > the scales then I lean slightly towards commenting above but not > noticeably changing the style of commentary.OK, I will move them. Ian.
Stefano Stabellini
2011-Dec-12 15:17 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Mon, 12 Dec 2011, Ian Campbell wrote:> On Mon, 2011-12-12 at 12:30 +0000, Ian Jackson wrote: > > Ian Campbell writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"): > > > On Mon, 2011-12-12 at 11:40 +0000, Ian Jackson wrote: > > > > Well, we have to have an internal version because we don''t want to > > > > call GC_INIT again, obviously. > > > > > > In this case it would take a ctx not a gc and it''s ok and expected for > > > libxl a function calling another libxl function to end up with another > > > gc in the inner function (it happens all the time). > > > > This is not allowed in functions which might generate events (ie, > > which might call libxl__event_occurred), because the application''s > > event callback will be called at an unexpected point in libxl''s > > execution. This has three problems: > > > > * There is a reentrancy hazard. Exactly whether this is a problem in > > a specific case is difficult to analyse; hence the recording of > > pending callbacks in the gc, so that they can be delayed until the > > gc is freed. > > > > * The application''s callbacks will be called with the libxl ctx > > locked. This might result in deadlock. > > > > * The application''s callbacks might be called in the wrong order > > because the inner gc (containing later events) is unwound before > > the outer gc (containing earlier events). > > > > In general this means that functions which lock the ctx must not > > allocate an inner gc.this is quite an important limitation and change in behaviour!> I was a little surprised when I looked when writing my previous reply > that LIBXL_INITGC doesn''t actually take nesting into account. I had > expected that LIBXL_INITGC would return (or somehow chain) the existing > GC when libxl is calling itself such that all the freeing work (and now > callbacks) would only happen when exiting the final frame. > > It''s probably not so important for memory allocation cleanup but it > would be a semantically useful change for the callbacks if we could > arrange for them to happen only on final exit of the library -- exactly > because of the difficulty of reasoning about things otherwise. Alas I > can''t think of a good way to do this since the ctx can be shared, thread > local storage would be one or libxl__gc_owner could return a special > "nested ctx" instead of the real outer ctx, but, ick.I think that using TLS to increase/decrease a nesting counter would OK in this case. We could have a libxl__enter and a libxl__exit function that take care it this. Modifying libxl__gc_owner could lead to errors because it doesn''t handle the case in which an externally visible function calls another externally visible function: libxl__gc_owner wouldn''t even be called in this case.> If we can''t figure a way round this then the restriction about libxl not > calling into itself via its own public interfaces should be documented > (apologies if I''ve simply missed that bit, I did go and look because I > thought I recalled seeing it, but I didn''t find it, I think I was > thinking about the comment associated with the CTX lock). In particular > if the restriction is that you cannot call public API functions which > might generate events from within libxl then those functions need to be > clearly annotated as potentially generating events.Right.
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> On Mon, 12 Dec 2011, Ian Campbell wrote: > > On Mon, 2011-12-12 at 12:30 +0000, Ian Jackson wrote: > > > In general this means that functions which lock the ctx must not > > > allocate an inner gc. > > this is quite an important limitation and change in behaviour!Luckily I have only introduced the ctx lock in this series so there is no existing code which violates this rule.> > It''s probably not so important for memory allocation cleanup but it > > would be a semantically useful change for the callbacks if we could > > arrange for them to happen only on final exit of the library -- exactly > > because of the difficulty of reasoning about things otherwise. Alas I > > can''t think of a good way to do this since the ctx can be shared, thread > > local storage would be one or libxl__gc_owner could return a special > > "nested ctx" instead of the real outer ctx, but, ick. > > I think that using TLS to increase/decrease a nesting counter would OK > in this case. We could have a libxl__enter and a libxl__exit function > that take care it this. > > Modifying libxl__gc_owner could lead to errors because it doesn''t handle > the case in which an externally visible function calls another > externally visible function: libxl__gc_owner wouldn''t even be called in > this case.I suggested to Ian the moral equivalent of: #define CTX_LOCK \ <previous implementation> \ ctx->recursive_lock_counter++ #define GC_INIT \ CTX_LOCK; \ assert(ctx->recursive_lock_counter==1); \ CTX_UNLOCK but I don''t think this is really very nice. I think the answer is to write a comment saying that it is forbidden to allocate a new gc with the ctx locked. Ian.
Stefano Stabellini
2011-Dec-12 19:24 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Mon, 12 Dec 2011, Ian Jackson wrote:> > > It''s probably not so important for memory allocation cleanup but it > > > would be a semantically useful change for the callbacks if we could > > > arrange for them to happen only on final exit of the library -- exactly > > > because of the difficulty of reasoning about things otherwise. Alas I > > > can''t think of a good way to do this since the ctx can be shared, thread > > > local storage would be one or libxl__gc_owner could return a special > > > "nested ctx" instead of the real outer ctx, but, ick. > > > > I think that using TLS to increase/decrease a nesting counter would OK > > in this case. We could have a libxl__enter and a libxl__exit function > > that take care it this. > > > > Modifying libxl__gc_owner could lead to errors because it doesn''t handle > > the case in which an externally visible function calls another > > externally visible function: libxl__gc_owner wouldn''t even be called in > > this case. > > I suggested to Ian the moral equivalent of: > > #define CTX_LOCK \ > <previous implementation> \ > ctx->recursive_lock_counter++ > > #define GC_INIT \ > CTX_LOCK; \ > assert(ctx->recursive_lock_counter==1); \ > CTX_UNLOCK > > but I don''t think this is really very nice. > > > I think the answer is to write a comment saying that it is forbidden > to allocate a new gc with the ctx locked.Why not handle the case correctly in the first place? It is certainly better than an assert or a comment, don''t you think? Ideally the code should be easy enough to understand without a comment. This is what I have in mind: diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index cd613f7..94bdbba 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -63,6 +63,12 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, * only as an initialiser, not as an expression. */ memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); + if(pthread_key_create(&ctx->tls_key, NULL) < 0) { + LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, + "cannot create tls key"); + return ERROR_FAIL; + } + if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" "failed to stat %s", XENSTORE_PID_FILE); diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index 34edaf3..eef3815 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -19,6 +19,7 @@ #include <stdarg.h> #include <string.h> +#include <pthread.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -65,17 +66,41 @@ int libxl__ptr_add(libxl__gc *gc, void *ptr) return 0; } +libxl__gc *libxl__init_gc(libxl_ctx *ctx) +{ + libxl__gc *gc = (libxl__gc *) pthread_getspecific(ctx->tls_key); + if (gc == NULL) { + gc = (libxl__gc *) malloc(sizeof(libxl__gc)); + if (gc == NULL) + return NULL; + gc->alloc_maxsize = 0; + gc->alloc_ptrs = 0; + gc->owner = ctx; + gc->nested = 1; + pthread_setspecific(ctx->tls_key, gc); + } else { + gc->nested++; + } + return gc; +} + void libxl__free_all(libxl__gc *gc) { void *ptr; int i; + gc->nested--; + if (gc->nested > 0) + return; + for (i = 0; i < gc->alloc_maxsize; i++) { ptr = gc->alloc_ptrs[i]; gc->alloc_ptrs[i] = NULL; free(ptr); } free(gc->alloc_ptrs); + pthread_setspecific(CTX->tls_key, NULL); + free(gc); } void *libxl__zalloc(libxl__gc *gc, int bytes) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index b479c49..50e6b33 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -91,6 +91,8 @@ struct libxl__ctx { xc_interface *xch; struct xs_handle *xsh; + pthread_key_t tls_key; + pthread_mutex_t lock; /* protects data structures hanging off the ctx */ /* Always use CTX_LOCK and CTX_UNLOCK to manipulate this. * @@ -138,9 +140,9 @@ typedef struct { int alloc_maxsize; void **alloc_ptrs; libxl_ctx *owner; + int nested; } libxl__gc; -#define LIBXL_INIT_GC(ctx) (libxl__gc){ .alloc_maxsize = 0, .alloc_ptrs = 0, .owner = ctx } static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc) { return gc->owner; @@ -670,7 +672,8 @@ libxl__device_model_version_running(libxl__gc *gc, uint32_t domid); * as a local variable. */ -#define GC_INIT(ctx) libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) } +_hidden libxl__gc *libxl__init_gc(struct libxl__ctx *ctx); +#define GC_INIT(ctx) libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM; #define GC_FREE libxl__free_all(gc) #define CTX libxl__gc_owner(gc) --- I like this approach because it uses malloc for gc allocation so it can be reused for your following patches that need a gc that lives out of the function. This way we don''t have two special cases but a single approach that works everywhere and another comment that probably doesn''t need to be read anymore. I also think that it makes the code easier to read and understand. However in case you would like to see how would this patch look, keeping the gc allocation on the stack, I have appended a version of it that uses alloca instead of malloc. P.S. please note that the inline patch as it is doesn''t compile because some libxl function don''t return an error but they return a pointer, something that should be changed anyway. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Mon, 2011-12-12 at 19:24 +0000, Stefano Stabellini wrote:> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index cd613f7..94bdbba 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -63,6 +63,12 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > * only as an initialiser, not as an expression. */ > memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); > > + if(pthread_key_create(&ctx->tls_key, NULL) < 0) { > + LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, > + "cannot create tls key"); > + return ERROR_FAIL;You need a corresponding pthread_key_delete in the free function.> [...]> @@ -65,17 +66,41 @@ int libxl__ptr_add(libxl__gc *gc, void *ptr) > return 0; > } > > +libxl__gc *libxl__init_gc(libxl_ctx *ctx) > +{ > + libxl__gc *gc = (libxl__gc *) pthread_getspecific(ctx->tls_key); > + if (gc == NULL) { > + gc = (libxl__gc *) malloc(sizeof(libxl__gc)); > + if (gc == NULL) > + return NULL; > + gc->alloc_maxsize = 0; > + gc->alloc_ptrs = 0; > + gc->owner = ctx; > + gc->nested = 1; > + pthread_setspecific(ctx->tls_key, gc);pthread_setspecific can fail.> [...]> void libxl__free_all(libxl__gc *gc) > { > void *ptr; > int i; > > + gc->nested--; > + if (gc->nested > 0) > + return; > + > for (i = 0; i < gc->alloc_maxsize; i++) { > ptr = gc->alloc_ptrs[i]; > gc->alloc_ptrs[i] = NULL; > free(ptr); > } > free(gc->alloc_ptrs); > + pthread_setspecific(CTX->tls_key, NULL);As above this can also fail. I think this one might be a bit harder to deal with in general.> + free(gc); > } >Ian.
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> +#define GC_INIT(ctx) libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM;I think we should avoid macros which return from their containing function, unless they are unavoidable. Only event-generating libxl entrypoints need to know about the special rules for handling the lock and ctx. The set of event-generating entrypoints to libxl is bounded - they are all part of the event generation core. Also, what you are doing here complicates the usual, simple, case. I would prefer to keep the case that can be simple, simple. So I think in this case it is better to document the restrictions rather than try to abolish them with additional behind-the-scenes machinery. See also Ian C''s comments. Ian.
Stefano Stabellini
2011-Dec-13 17:42 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Tue, 13 Dec 2011, Ian Jackson wrote:> Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"): > > +#define GC_INIT(ctx) libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM; > > I think we should avoid macros which return from their containing > function, unless they are unavoidable. > > Only event-generating libxl entrypoints need to know about the special > rules for handling the lock and ctx. The set of event-generating > entrypoints to libxl is bounded - they are all part of the event > generation core. > > Also, what you are doing here complicates the usual, simple, case. > I would prefer to keep the case that can be simple, simple. > > So I think in this case it is better to document the restrictions > rather than try to abolish them with additional behind-the-scenes > machinery.I would agree with you if you were not about to introduce an even more complicate machinery in the library. A machinery that needs a different entry point compared to regular libxl functions. Actually I think that introducing different modes of operations in the same codebase is very confusing for everyone that works on it. No matter how well you document them. The kernel is very well documented, but still it is difficult to understand when you can sleep and when you cannot. So I am up for anything that would remove this duality. Also it is very hard to predict whether the event-generating entrypoints are going to stay bounded. That said, there is a very easy solution to this problem: we remove the macro, that I personally dislike anyway, and we open code the check at the beginning of every function. Now that we are using C99 there isn''t any problem with doing this. It is also much easier to understand what is going on this way, no hidden behaviors, nothing returning behind your back, or declaring a new variable a macro. We could easily make it comply the CODE_STYLE with the addition of a single line. @@ -235,7 +241,7 @@ int libxl__domain_rename(libxl__gc *gc, uint32_t domid, int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid, const char *old_name, const char *new_name) { - GC_INIT(ctx); + libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM; int rc; rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL); GC_FREE;
On Tue, 2011-12-13 at 17:42 +0000, Stefano Stabellini wrote:> So I am up for anything that would remove this duality.That''s a very strong statement to make about a patch which Ian hasn''t posted yet (nor, I suspect, has he even finished writing it). Rather than entrenching positions now lets wait and evaluate that patch on its merits. Ian.
Stefano Stabellini
2011-Dec-13 18:17 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Tue, 13 Dec 2011, Ian Campbell wrote:> On Tue, 2011-12-13 at 17:42 +0000, Stefano Stabellini wrote: > > So I am up for anything that would remove this duality. > > That''s a very strong statement to make about a patch which Ian hasn''t > posted yet (nor, I suspect, has he even finished writing it). > > Rather than entrenching positions now lets wait and evaluate that patch > on its merits.I am not against this "future" patch or even the concept behind it. And I am certainly not going to argue against a patch I haven''t even seen yet. What I am saying is that if we need a malloc allocated gc is the near future then I am very strongly in favor of changing the allocation of all of them rather than only some. Also, there is the matter of the recursive lock, that started this discussion and brought us here.
Stefano Stabellini
2012-Jan-12 13:40 UTC
Re: [PATCH 15/15] libxl: New event generation API
On Tue, 13 Dec 2011, Ian Campbell wrote:> On Mon, 2011-12-12 at 19:24 +0000, Stefano Stabellini wrote: > > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > > index cd613f7..94bdbba 100644 > > --- a/tools/libxl/libxl.c > > +++ b/tools/libxl/libxl.c > > @@ -63,6 +63,12 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, > > * only as an initialiser, not as an expression. */ > > memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock)); > > > > + if(pthread_key_create(&ctx->tls_key, NULL) < 0) { > > + LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, > > + "cannot create tls key"); > > + return ERROR_FAIL; > > You need a corresponding pthread_key_delete in the free function.good point> > [...] > > > @@ -65,17 +66,41 @@ int libxl__ptr_add(libxl__gc *gc, void *ptr) > > return 0; > > } > > > > +libxl__gc *libxl__init_gc(libxl_ctx *ctx) > > +{ > > + libxl__gc *gc = (libxl__gc *) pthread_getspecific(ctx->tls_key); > > + if (gc == NULL) { > > + gc = (libxl__gc *) malloc(sizeof(libxl__gc)); > > + if (gc == NULL) > > + return NULL; > > + gc->alloc_maxsize = 0; > > + gc->alloc_ptrs = 0; > > + gc->owner = ctx; > > + gc->nested = 1; > > + pthread_setspecific(ctx->tls_key, gc); > > pthread_setspecific can fail.right, I''ll handle that> > [...] > > > void libxl__free_all(libxl__gc *gc) > > { > > void *ptr; > > int i; > > > > + gc->nested--; > > + if (gc->nested > 0) > > + return; > > + > > for (i = 0; i < gc->alloc_maxsize; i++) { > > ptr = gc->alloc_ptrs[i]; > > gc->alloc_ptrs[i] = NULL; > > free(ptr); > > } > > free(gc->alloc_ptrs); > > + pthread_setspecific(CTX->tls_key, NULL); > > As above this can also fail. I think this one might be a bit harder to > deal with in general.this pthread_setspecific call, with the NULL paramter, can only fail if the key is invalid, so I think that we don''t need to handle that error.
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> +#define GC_INIT(ctx) libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM;One of my key objection to this is here. I think that a convenience macro should be written to avoid returning from the calling function whereever possible. And here, it is possible. My other key objection is that I disapprove of the additional dynamic allocation step, which provides additonal scope for bugs. Dynamic allocation with manual memory management should be avoided where it is not necessary. In general code should be structured so as to minimise undetected mistakes by the programmer, which this is not. Indeed your first version attempt at this approach has two such bugs! Converseley the programming mistake you are trying to eliminate, of calling an event-generating function from elsewhere in libxl, is not a trivial mistake. Firstly, it can only result from a fundamentally wrongheaded approach to writing an asynchronous function. In the correct approach the desire to call an event-generation function (whether a slow function like a synchronous ao call, or such as an event callback) from other non-event-related libxl functions should not arise. Secondly, the restriction is now enforced by the type system. So the programmer can forget about this restriction unless they are actually modifying the core event machinery. Ian.
Stefano Stabellini writes ("Re: [Xen-devel] [PATCH 15/15] libxl: New event generation API"):> +_hidden libxl__gc *libxl__init_gc(struct libxl__ctx *ctx); > +#define GC_INIT(ctx) libxl__gc *gc = libxl__init_gc(ctx); if (gc == NULL) return ERROR_NOMEM;Also of course not all functions which use GC_INIT currently return a libxl error code. Here is a counterexample: libxl__qmp_handler *libxl__qmp_initialize(libxl_ctx *ctx, uint32_t domid) { int ret = 0; libxl__qmp_handler *qmp = NULL; char *qmp_socket; GC_INIT(ctx); Ian.