All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v2 00/13] New event API
@ 2011-10-28 18:36 Ian Jackson
  2011-10-28 18:36 ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Jackson
  2011-10-31 10:11 ` [PATCH RFC v2 00/13] New event API Ian Campbell
  0 siblings, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:36 UTC (permalink / raw)
  To: xen-devel

This is a revised RFC version of my event handling API proposal.

It consists of 10 rather uninteresting preparatory, stylistic
and bugfix patches, plus 3 with some meat in:
  02/13  libxenstore: Provide xs_check_watch
  12/13  libxl: New API for providing OS events to libxl
  13/13  libxl: New event generation API

This series contains an implementation of almost everything, and
builds apart from the lack of libxl_event_free, but it has not been
executed at all.

So at this stage a very detailed code review, particularly of 12 and
13 is probably not appropriate.  However, this is hopefully a
near-final version of the external and internal interfaces so it would
be worth looking at those.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct
  2011-10-28 18:36 [PATCH RFC v2 00/13] New event API Ian Jackson
@ 2011-10-28 18:36 ` Ian Jackson
  2011-10-28 18:37   ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Jackson
  2011-10-31  9:34   ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Campbell
  2011-10-31 10:11 ` [PATCH RFC v2 00/13] New event API Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:36 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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>
---
 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 2e26ac6..31adbc8 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -181,18 +181,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) */
 
 /* from xl_dom */
diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
index e41f962..56a7c7b 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch
  2011-10-28 18:36 ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Jackson
@ 2011-10-28 18:37   ` Ian Jackson
  2011-10-28 18:37     ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Jackson
  2011-10-31  9:39     ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Campbell
  2011-10-31  9:34   ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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 c72ea83..96e4b7a 100644
--- a/tools/xenstore/xs.c
+++ b/tools/xenstore/xs.c
@@ -132,7 +132,20 @@ 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 flags = fcntl(fd, F_GETFL);
+	if (flags == -1)
+		return;
+
+	if (nonblock)
+		flags |= O_NONBLOCK;
+	else
+		flags &= ~O_NONBLOCK;
+
+	fcntl(fd, F_SETFL, flags);
+}
 
 int xs_fileno(struct xs_handle *h)
 {
@@ -327,8 +340,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;
 
@@ -336,18 +357,31 @@ 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) {
+		int e = errno;
+		setnonblock(fd, 0);
+		errno = e;
+	}
+	return false;
 }
 
 #ifdef XSTEST
@@ -376,7 +410,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);
@@ -695,7 +729,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;
@@ -709,14 +744,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) */
@@ -762,6 +803,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).
  */
@@ -942,11 +1001,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;
@@ -958,7 +1023,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;
 	}
@@ -968,7 +1033,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;
 	}
@@ -1023,7 +1088,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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h
  2011-10-28 18:37   ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Jackson
@ 2011-10-28 18:37     ` Ian Jackson
  2011-10-28 18:37       ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Jackson
  2011-10-31  9:43       ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Campbell
  2011-10-31  9:39     ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
 COPYING                              |    8 +
 tools/libxl/Makefile                 |   10 +-
 tools/libxl/bsd-sys-queue-h-seddery  |   70 +++
 tools/libxl/external/README          |   13 +
 tools/libxl/external/bsd-queue.3     | 1044 ++++++++++++++++++++++++++++++++++
 tools/libxl/external/bsd-sys-queue.h |  637 +++++++++++++++++++++
 6 files changed, 1779 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-queue.3
 create mode 100644 tools/libxl/external/bsd-sys-queue.h

diff --git a/COPYING b/COPYING
index 07535ad..524542d 100644
--- a/COPYING
+++ b/COPYING
@@ -18,6 +18,14 @@ GPLv2. See the FSF's definition of GPL compatibility:
 And how this applies to a range of open source licenses:
  http://www.gnu.org/licenses/license-list.html
 
+Additionally, the documentation file tools/libxl/external/bsd-queue.3
+has the 4-clause BSD licence.  It is present in the Xen source tree
+for reference purposes for people developing Xen.  It is not installed
+by "make install" and is bundled in the source only for convenience of
+distribution.  We do not intend that we or Xen users or distributors
+should make any reference to "features or use" of that manpage.
+
+
 Licensing Exceptions (the relaxed BSD-style license)
 ----------------------------------------------------
 
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 51e5132..f23661a 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..f3a3ac4
--- /dev/null
+++ b/tools/libxl/external/README
@@ -0,0 +1,13 @@
+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-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
+
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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute
  2011-10-28 18:37     ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Jackson
@ 2011-10-28 18:37       ` Ian Jackson
  2011-10-28 18:37         ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Jackson
  2011-10-31  9:46         ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Campbell
  2011-10-31  9:43       ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

This provides for fields in libxl datatypes which are only present in
the C version of structures.  This is useful, for example, 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 +++-
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py
index 6697ac5..ed5358d 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.c_only:
+        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 05cba88..83a9426 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.c_only = kwargs.setdefault('c_only', False)
+
         if typename is None: # Anonymous type
             self.typename = None
             self.rawname = None
@@ -50,7 +52,7 @@ class Type(object):
 
         self.autogenerate_destructor = kwargs.setdefault('autogenerate_destructor', True)
 
-        if self.typename is not None:
+        if self.typename is not None and not self.c_only:
             self.json_fn = kwargs.setdefault('json_fn', self.typename + "_gen_json")
         else:
             self.json_fn = kwargs.setdefault('json_fn', None)
-- 
1.7.2.5

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags
  2011-10-28 18:37       ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Jackson
@ 2011-10-28 18:37         ` Ian Jackson
  2011-10-28 18:37           ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Jackson
  2011-10-31  9:47           ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Campbell
  2011-10-31  9:46         ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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>
---
 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 e82b706..c4efbf3 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-10-28 18:37         ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Jackson
@ 2011-10-28 18:37           ` Ian Jackson
  2011-10-28 18:37             ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Jackson
  2011-10-31  9:50             ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Campbell
  2011-10-31  9:47           ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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 f23661a..a3727ab 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 07/13] libxl: internal convenience macros
  2011-10-28 18:37           ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Jackson
@ 2011-10-28 18:37             ` Ian Jackson
  2011-10-28 18:37               ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Jackson
  2011-10-31  9:53               ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Campbell
  2011-10-31  9:50             ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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>
---
 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 31adbc8..8649788 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -555,6 +555,54 @@ _hidden void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj);
 
 _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
 
+
+/*
+ * 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 08/13] libxl: Rationalise #includes
  2011-10-28 18:37             ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Jackson
@ 2011-10-28 18:37               ` Ian Jackson
  2011-10-28 18:37                 ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Jackson
  2011-10-31  9:55                 ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Campbell
  2011-10-31  9:53               ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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>
---
 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     |    2 --
 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       |    4 ++--
 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(+), 40 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 064fbc4..5d448af 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 1e735a8..396aac6 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 1024
 
diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c
index 12cc0b1..f65a898 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_destroy(libxl_cpuid_policy_list *p_cpuid_list)
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 68d0fc3..70705af 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_destroy(libxl_domain_config *d_config)
 {
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 88cd990..8b5fc4a 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -24,8 +24,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-
-#include "libxl.h"
 #include "libxl_internal.h"
 
 static const char *string_of_kinds[] = {
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index d6ad85b..e18bac7 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 718281a..430b3d0 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 d6199d4..e981679 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 3993d8e..dd31f25 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 8649788..6d9da2c 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 11f65fc..a4208f3 100644
--- a/tools/libxl/libxl_json.c
+++ b/tools/libxl/libxl_json.c
@@ -12,13 +12,13 @@
  * GNU Lesser General Public License for more details.
  */
 
+#include "libxl_osdeps.h"
+
 #include <assert.h>
-#include <string.h>
 
 #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 64f662d..fa80056 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 33dd060..9eac108 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 618f20f..0eefe4d 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 dce9d8b..7ea2d2c 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 56a7c7b..f85e867 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-10-28 18:37               ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Jackson
@ 2011-10-28 18:37                 ` Ian Jackson
  2011-10-28 18:37                   ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Jackson
  2011-10-31 10:03                   ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Campbell
  2011-10-31  9:55                 ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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>
---
 tools/libxl/libxl.c          |    3 +++
 tools/libxl/libxl_internal.h |   16 ++++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 5d448af..a3c9807 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -40,6 +40,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
 {
     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;
@@ -53,6 +54,8 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
     memset(ctx, 0, sizeof(libxl_ctx));
     ctx->lg = lg;
 
+    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 6d9da2c..79a9de4 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,9 @@ struct libxl__ctx {
     xc_interface *xch;
     struct xs_handle *xsh;
 
+    pthread_mutex_t lock; /* protects data structures hanging off the ctx */
+      /* always use MUTEX_LOCK and MUTEX_UNLOCK to manipulate this */
+
     /* 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 */
@@ -577,6 +581,18 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
 #define CTX           libxl__gc_owner(gc)
 
 
+#define MUTEX_LOCK do {                                 \
+        int mutex_r = pthread_mutex_lock(&CTX->lock);   \
+        assert(!mutex_r);                               \
+    } while(0)
+
+#define MUTEX_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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct
  2011-10-28 18:37                 ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Jackson
@ 2011-10-28 18:37                   ` Ian Jackson
  2011-10-28 18:37                     ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Jackson
  2011-10-31 10:04                     ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Campbell
  2011-10-31 10:03                   ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

Signed-off-by: Ian Jackson <ian.jackson@eu.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 dd31f25..df2b7f8 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 79a9de4..fe64d34 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent
  2011-10-28 18:37                   ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Jackson
@ 2011-10-28 18:37                     ` Ian Jackson
  2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
  2011-10-31 10:05                       ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Campbell
  2011-10-31 10:04                     ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Campbell
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

Signed-off-by: Ian Jackson <ian.jackson@eu.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 df2b7f8..62e7fba 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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl
  2011-10-28 18:37                     ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Jackson
@ 2011-10-28 18:37                       ` Ian Jackson
  2011-10-28 18:37                         ` [PATCH RFC v2 13/13] libxl: New event generation API Ian Jackson
                                           ` (2 more replies)
  2011-10-31 10:05                       ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Campbell
  1 sibling, 3 replies; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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    |  704 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_event.h    |  185 +++++++++++
 tools/libxl/libxl_internal.h |  212 +++++++++++++-
 6 files changed, 1131 insertions(+), 3 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 a3727ab..0680812 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 a3c9807..4d619ab 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -56,6 +56,16 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
 
     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);
@@ -85,10 +95,25 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
 
 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_destroy(&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 5d28ff9..da06ed2 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"
@@ -221,6 +222,9 @@ enum {
     ERROR_INVAL = -6,
     ERROR_BADFAIL = -7,
     ERROR_GUEST_TIMEDOUT = -8,
+    ERROR_NOT_READY = -9,
+    ERROR_OSEVENT_REG_FAIL = -10,
+    ERROR_BUFFERFULL = -11,
 };
 
 #define LIBXL_VERSION 0
@@ -539,6 +543,8 @@ const char *libxl_xen_script_dir_path(void);
 const char *libxl_lock_dir_path(void);
 const char *libxl_run_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..9283b04
--- /dev/null
+++ b/tools/libxl/libxl_event.c
@@ -0,0 +1,704 @@
+/*
+ * 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"
+
+#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);
+
+    MUTEX_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:
+    MUTEX_UNLOCK;
+    return rc;
+}
+
+int libxl__ev_fd_modify(libxl__gc *gc, libxl__ev_fd *ev, short events) {
+    int rc;
+
+    MUTEX_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:
+    MUTEX_UNLOCK;
+    return rc;
+}
+
+void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev) {
+    MUTEX_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:
+    MUTEX_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;
+    
+    MUTEX_LOCK;
+
+    rc = time_register_finite(gc, ev, abs);
+    if (rc) goto out;
+
+    ev->func = func;
+
+    rc = 0;
+ out:
+    MUTEX_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;
+
+    MUTEX_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:
+    MUTEX_UNLOCK;
+    return 0;
+}
+
+int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev,
+                              struct timeval abs) {
+    int rc;
+
+    MUTEX_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:
+    MUTEX_UNLOCK;
+    return rc;
+}
+
+int libxl__ev_time_modify_rel(libxl__gc *gc, libxl__ev_time *ev,
+                              int milliseconds) {
+    struct timeval abs;
+    int rc;
+
+    MUTEX_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:
+    MUTEX_UNLOCK;
+    return 0;
+}
+
+void libxl__ev_time_deregister(libxl__gc *gc, libxl__ev_time *ev) {
+    MUTEX_LOCK;
+
+    if (!libxl__ev_time_isregistered(ev))
+        goto out;
+        
+    time_deregister(gc, ev);
+    ev->func = 0;
+
+ out:
+    MUTEX_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;
+
+    MUTEX_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++;
+
+    rc = xs_watch(CTX->xsh, path, watch_token(gc, slotnum, w->counterval));
+    if (rc) {
+        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;
+
+    MUTEX_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);
+    MUTEX_UNLOCK;
+    return rc;
+}
+
+void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch *w) {
+    /* it is legal to deregister from within _callback */
+    MUTEX_LOCK;
+
+    if (w->slotnum >= 0) {
+        char *token = watch_token(gc, w->slotnum, w->counterval);
+        int rc = xs_unwatch(CTX->xsh, w->path, token);
+        if (rc)
+            /* 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;
+
+    MUTEX_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);
+    MUTEX_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;
+    }
+
+    MUTEX_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);
+    MUTEX_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);
+    }
+
+    MUTEX_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);
+    MUTEX_LOCK;
+    ctx->osevent_hooks = hooks;
+    ctx->osevent_user = user;
+    MUTEX_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);
+    MUTEX_LOCK;
+    assert(!CTX->osevent_in_hook);
+
+    assert(fd == ev->fd);
+    revents &= ev->events;
+    if (revents)
+        ev->func(gc, ev, fd, ev->events, revents);
+
+    MUTEX_UNLOCK;
+    GC_FREE;
+}
+
+void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl) {
+    libxl__ev_time *ev = for_libxl;
+
+    GC_INIT(ctx);
+    MUTEX_LOCK;
+
+    assert(!ev->infinite);
+    LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
+    ev->func(gc, ev, &ev->abs);
+
+    MUTEX_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) {
+    libxl__log(CTX, XTL_CRITICAL, errnoval, file, line,
+               "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..48c6277
--- /dev/null
+++ b/tools/libxl/libxl_event.h
@@ -0,0 +1,185 @@
+/*
+ * 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).
+   *
+   * 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 fe64d34..07bbe8d 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;
@@ -99,6 +162,21 @@ struct libxl__ctx {
     pthread_mutex_t lock; /* protects data structures hanging off the ctx */
       /* always use MUTEX_LOCK and MUTEX_UNLOCK to manipulate this */
 
+    int osevent_in_hook;
+    const libxl_osevent_hooks *osevent_hooks;
+    void *osevent_user;
+
+    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 +216,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(ctx) (libxl__gc){ .alloc_maxsize = 0, .alloc_ptrs = 0, .owner = ctx }
 static inline libxl_ctx *libxl__gc_owner(libxl__gc *gc)
@@ -205,6 +283,134 @@ _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) */
 
+
+/*
+ * 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);
+  /*
+   * 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__)
+
+
 /* 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);
@@ -441,6 +647,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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH RFC v2 13/13] libxl: New event generation API
  2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
@ 2011-10-28 18:37                         ` Ian Jackson
  2011-10-31 11:49                           ` Ian Campbell
  2011-10-31 12:15                         ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Campbell
  2011-11-07 10:42                         ` Stefano Stabellini
  2 siblings, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-10-28 18:37 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson

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          |  306 +++++++++++++++++++++++++++++------------
 tools/libxl/libxl.h          |   55 ++-------
 tools/libxl/libxl_event.c    |  182 +++++++++++++++++++++++---
 tools/libxl/libxl_event.h    |  172 +++++++++++++++++++++++
 tools/libxl/libxl_internal.c |    6 +
 tools/libxl/libxl_internal.h |   66 +++++++++
 tools/libxl/libxl_types.idl  |   35 ++++-
 tools/libxl/xl_cmdimpl.c     |  261 +++++++++++++++++++++---------------
 8 files changed, 815 insertions(+), 268 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 4d619ab..701763e 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -58,6 +58,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
 
     ctx->osevent_hooks = 0;
 
+    ctx->fd_polls = 0;
     ctx->fd_beforepolled = 0;
     LIBXL_LIST_INIT(&ctx->efds);
     LIBXL_TAILQ_INIT(&ctx->etimes);
@@ -66,6 +67,9 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
     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);
@@ -93,6 +97,13 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
     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;
@@ -100,6 +111,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);
@@ -111,6 +125,7 @@ int libxl_ctx_free(libxl_ctx *ctx)
     libxl_version_info_destroy(&ctx->version_info);
     if (ctx->xsh) xs_daemon_close(ctx->xsh);
 
+    free(ctx->fd_polls);
     free(ctx->fd_beforepolled);
     free(ctx->watch_slots);
 
@@ -610,117 +625,175 @@ 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;
-}
+    MUTEX_LOCK;
 
-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);
-    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:
-    libxl__free_all(&gc);
-    return rc;
+ all_reported:
+ out:
+
+    MUTEX_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;
+    
+    MUTEX_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:
+    MUTEX_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) {
+    MUTEX_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;
+    MUTEX_UNLOCK;
 }
 
-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);
-    char *path;
+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_domain_death *evg = (void*)watch;
+    int rc;
     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")) {
-        libxl__free_all(&gc);
-        return 0;
+    if (!value || strcmp(value,  "eject"))
+        return;
+
+    rc = libxl__xs_write(gc, XBT_NULL, wpath, "");
+    if (rc) {
+        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")) {
@@ -729,19 +802,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__free_all(&gc);
-    return 1;
+    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->vdev = strdup(vdev);
+    if (!evg->vdev) { rc = ERROR_NOMEM; goto out; }
+
+    uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
+    evg->domid = 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 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)
 {
     libxl__gc gc = LIBXL_INIT_GC(ctx);
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index da06ed2..4759c18 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_destroy(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"
@@ -295,51 +303,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 9283b04..9b0b6e0 100644
--- a/tools/libxl/libxl_event.c
+++ b/tools/libxl/libxl_event.c
@@ -487,9 +487,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;
 
@@ -500,9 +500,6 @@ int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
      * the fds array corresponds to a slot in fd_beforepolled.
      */
 
-    GC_INIT(ctx);
-    MUTEX_LOCK;
-
     if (*nfds_io) {
         /*
          * As an optimisation, we don't touch fd_beforepolled_used
@@ -574,16 +571,25 @@ int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
             *timeout_upd = our_timeout;
     }
 
-    MUTEX_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);
     MUTEX_LOCK;
+    int rc = beforepoll_unlocked(gc, nfds_io, fds, timeout_upd, now);
+    MUTEX_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);
 
@@ -619,12 +625,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);
+    MUTEX_LOCK;
+    afterpoll_unlocked(gc, nfds, fds, now);
     MUTEX_UNLOCK;
     GC_FREE;
 }
 
-
 /*
  * osevent hook and callback machinery
  */
@@ -682,11 +693,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";
@@ -696,6 +706,146 @@ 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);
+    }
+}
+
+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);
+    MUTEX_LOCK;
+    int rc = event_check_unlocked(gc, event_r, typemask, pred, pred_user);
+    MUTEX_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);
+    MUTEX_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_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.
+         */
+        MUTEX_UNLOCK;
+        libxl__free_all(gc);
+        MUTEX_LOCK;
+    }
+
+ out:
+    MUTEX_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 48c6277..c52addc 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.
+   */
+
+int 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.
+   */
+
 
 /*======================================================================*/
 
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index 62e7fba..202ba89 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 07bbe8d..51b807b 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -154,18 +154,56 @@ 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 MUTEX_LOCK and MUTEX_UNLOCK to manipulate this */
 
+    LIBXL_TAILQ_HEAD(, libxl_event) occurred;
+
     int osevent_in_hook;
     const libxl_osevent_hooks *osevent_hooks;
     void *osevent_user;
 
+    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;
@@ -177,6 +215,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 */
@@ -221,6 +264,7 @@ struct libxl__gc {
     int alloc_maxsize;
     void **alloc_ptrs;
     libxl_ctx *owner;
+    LIBXL_TAILQ_HEAD(, libxl_event) occurred_for_callback;
 };
 
 #define LIBXL_INIT_GC(ctx) (libxl__gc){ .alloc_maxsize = 0, .alloc_ptrs = 0, .owner = ctx }
@@ -392,6 +436,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);
@@ -403,6 +466,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).
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 93fb8cd..53c07ee 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"),
@@ -374,3 +369,33 @@ libxl_sched_credit = Struct("sched_credit", [
     ("weight", integer),
     ("cap", integer),
     ], destructor_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, c_only=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 a890ef1..4c4ad69 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1135,14 +1135,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;
@@ -1159,11 +1161,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;
@@ -1228,7 +1233,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;
@@ -1340,6 +1345,24 @@ 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) {
+            LOG("INTERNAL PROBLEM - ignoring unexpected event for"
+                " domain %d (expected %d)", (*event_r)->domid, domid);
+            libxl_event_free(ctx, *event_r);
+            continue;
+        }
+        return ret;
+    }
+}
+
 static int create_domain(struct domain_create *dom_info)
 {
     libxl_domain_config d_config;
@@ -1353,10 +1376,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;
@@ -1604,92 +1628,104 @@ 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 error_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 error_out;
+    }
+    while (1) {
+        libxl_event *event;
+        ret = domain_wait_event(&event);
+        if (ret) goto error_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_destroy(&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);
+            libxl_device_disk_destroy(&event->u.disk_eject.disk);
+            break;
+
+        default:
+            LOG("warning, got unexpected event type %d", event->type);
         }
-        libxl_free_event(&event);
+
+        libxl_event_free(ctx, event);
     }
 
 error_out:
@@ -2163,43 +2199,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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct
  2011-10-28 18:36 ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Jackson
  2011-10-28 18:37   ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Jackson
@ 2011-10-31  9:34   ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:34 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:36 +0100, Ian Jackson wrote:
> 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>

Obviously correct, (assuming it compiles, which is a safe assumption I
think ;-))):

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 2e26ac6..31adbc8 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -181,18 +181,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) */
>  
>  /* from xl_dom */
> diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
> index e41f962..56a7c7b 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;

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch
  2011-10-28 18:37   ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Jackson
  2011-10-28 18:37     ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Jackson
@ 2011-10-31  9:39     ` Ian Campbell
  2011-11-02 16:35       ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:39 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> +
> +out_false:
> +	if (nonblocking) {
> +		int e = errno;
> +		setnonblock(fd, 0);
> +		errno = e;
> +	}

Since setnonblock cannot itself return an error should it always
preserve errno on behalf of the caller?

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h
  2011-10-28 18:37     ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Jackson
  2011-10-28 18:37       ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Jackson
@ 2011-10-31  9:43       ` Ian Campbell
  2011-11-02 17:28         ` Anil Madhavapeddy
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:43 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> @@ -18,6 +18,14 @@ GPLv2. See the FSF's definition of GPL compatibility:
>  And how this applies to a range of open source licenses:
>   http://www.gnu.org/licenses/license-list.html
> 
> +Additionally, the documentation file tools/libxl/external/bsd-queue.3
> +has the 4-clause BSD licence.  It is present in the Xen source tree
> +for reference purposes for people developing Xen.  It is not installed
> +by "make install" and is bundled in the source only for convenience of
> +distribution.  We do not intend that we or Xen users or distributors
> +should make any reference to "features or use" of that manpage.

Anil pointed to the OpenBSD version of this page which has that clause
removed. It would simplify things to use their version (of the header
too for consistency)?  We are probably not comfortable with just
rescinding the clause ourselves?

Otherwise I'm happy with this, so:

Acked-by: Ian Campbell <Ian.campbell@citrix.com>

Also Roger previously supplied a

Tested-by: Roger Pau Monne <roger.pau@entel.upc.edu>

> +[...]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute
  2011-10-28 18:37       ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Jackson
  2011-10-28 18:37         ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Jackson
@ 2011-10-31  9:46         ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:46 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> This provides for fields in libxl datatypes which are only present in
> the C version of structures.  This is useful, for example, 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>

> ---
>  tools/libxl/gentest.py    |    2 ++
>  tools/libxl/libxltypes.py |    4 +++-
>  2 files changed, 5 insertions(+), 1 deletions(-)
> 
> diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py
> index 6697ac5..ed5358d 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.c_only:
> +        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 05cba88..83a9426 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.c_only = kwargs.setdefault('c_only', False)
> +
>          if typename is None: # Anonymous type
>              self.typename = None
>              self.rawname = None
> @@ -50,7 +52,7 @@ class Type(object):
>  
>          self.autogenerate_destructor = kwargs.setdefault('autogenerate_destructor', True)
>  
> -        if self.typename is not None:
> +        if self.typename is not None and not self.c_only:
>              self.json_fn = kwargs.setdefault('json_fn', self.typename + "_gen_json")
>          else:
>              self.json_fn = kwargs.setdefault('json_fn', None)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags
  2011-10-28 18:37         ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Jackson
  2011-10-28 18:37           ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Jackson
@ 2011-10-31  9:47           ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:47 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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 e82b706..c4efbf3 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:

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-10-28 18:37           ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Jackson
  2011-10-28 18:37             ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Jackson
@ 2011-10-31  9:50             ` Ian Campbell
  2011-11-02 16:36               ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:50 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, 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 suspect there isn't much scope for abuse of this capability but would
a few words of guidance in CODING_STYLE make sense?

> ---
>  tools/libxl/Makefile |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index f23661a..a3727ab 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)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 07/13] libxl: internal convenience macros
  2011-10-28 18:37             ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Jackson
  2011-10-28 18:37               ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Jackson
@ 2011-10-31  9:53               ` Ian Campbell
  2011-11-02 16:37                 ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:53 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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>
> ---
>  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 31adbc8..8649788 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -555,6 +555,54 @@ _hidden void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj);
>  
>  _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
>  
> +
> +/*
> + * 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) }

Tricksy, I like it ;-)

Acked-by: Ian Campbell <ian.campbell@citrix.com>

Is there a massive conversion patch somewhere downseries?

> +#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
>  
>  /*

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 08/13] libxl: Rationalise #includes
  2011-10-28 18:37               ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Jackson
  2011-10-28 18:37                 ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Jackson
@ 2011-10-31  9:55                 ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31  9:55 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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     |    2 --
>  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       |    4 ++--
>  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(+), 40 deletions(-)
> 
> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 064fbc4..5d448af 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 1e735a8..396aac6 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 1024
> 
> diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c
> index 12cc0b1..f65a898 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_destroy(libxl_cpuid_policy_list *p_cpuid_list)
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 68d0fc3..70705af 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_destroy(libxl_domain_config *d_config)
>  {
> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
> index 88cd990..8b5fc4a 100644
> --- a/tools/libxl/libxl_device.c
> +++ b/tools/libxl/libxl_device.c
> @@ -24,8 +24,6 @@
>  #include <unistd.h>
>  #include <fcntl.h>
> 
> -
> -#include "libxl.h"
>  #include "libxl_internal.h"
> 
>  static const char *string_of_kinds[] = {
> diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
> index d6ad85b..e18bac7 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 718281a..430b3d0 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 d6199d4..e981679 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 3993d8e..dd31f25 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 8649788..6d9da2c 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 11f65fc..a4208f3 100644
> --- a/tools/libxl/libxl_json.c
> +++ b/tools/libxl/libxl_json.c
> @@ -12,13 +12,13 @@
>   * GNU Lesser General Public License for more details.
>   */
> 
> +#include "libxl_osdeps.h"
> +
>  #include <assert.h>
> -#include <string.h>
> 
>  #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 64f662d..fa80056 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 33dd060..9eac108 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 618f20f..0eefe4d 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 dce9d8b..7ea2d2c 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 56a7c7b..f85e867 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
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-10-28 18:37                 ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Jackson
  2011-10-28 18:37                   ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Jackson
@ 2011-10-31 10:03                   ` Ian Campbell
  2011-11-02 16:38                     ` Ian Jackson
  2011-11-28 15:47                     ` Ian Jackson
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 10:03 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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>
> ---
>  tools/libxl/libxl.c          |    3 +++
>  tools/libxl/libxl_internal.h |   16 ++++++++++++++++
>  2 files changed, 19 insertions(+), 0 deletions(-)
> 
> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 5d448af..a3c9807 100644
> --- a/tools/libxl/libxl.c
> +++ b/tools/libxl/libxl.c
> @@ -40,6 +40,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
>  {
>      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;
> @@ -53,6 +54,8 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, xentoollog_logger * lg)
>      memset(ctx, 0, sizeof(libxl_ctx));
>      ctx->lg = lg;
>  
> +    memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));

Is this subtly different to
       ctx->lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
in some way I'm missing?

> +
>      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 6d9da2c..79a9de4 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,9 @@ struct libxl__ctx {
>      xc_interface *xch;
>      struct xs_handle *xsh;
>  
> +    pthread_mutex_t lock; /* protects data structures hanging off the ctx */
> +      /* always use MUTEX_LOCK and MUTEX_UNLOCK to manipulate this */

MUTEX is something of an implementation detail (although I admit we are
unlikely to use anything else), perhaps CTX_(UN)LOCK?

Perhaps give the variable a less obvious name to help discourage direct
use?

> +
>      /* 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 */
> @@ -577,6 +581,18 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
>  #define CTX           libxl__gc_owner(gc)
>  
> 
> +#define MUTEX_LOCK do {                                 \
> +        int mutex_r = pthread_mutex_lock(&CTX->lock);   \
> +        assert(!mutex_r);                               \

This assert is to catch EINVAL ("the mutex has not been properly
initialized") rather than EDEADLK ("the mutex is already locked by the
calling thread") since we asked for a non-error-checking recursive lock?

Since it is OK to take this lock recursively then it might be as well to
say so explicitly?

This is the first lock in libxl so I guess there isn't much of a locking
hierarchy yet. Are there any particular considerations which a caller
must make wrt its own locking?

> +    } while(0)
> +
> +#define MUTEX_UNLOCK do {                               \
> +        int mutex_r = pthread_mutex_unlock(&CTX->lock); \
> +        assert(!mutex_r);                               \
> +    } while(0)
> +        
> +
> +
>  /*
>   * Inserts "elm_new" into the sorted list "head".
>   *

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct
  2011-10-28 18:37                   ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Jackson
  2011-10-28 18:37                     ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Jackson
@ 2011-10-31 10:04                     ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 10:04 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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 dd31f25..df2b7f8 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 79a9de4..fe64d34 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) */

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent
  2011-10-28 18:37                     ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Jackson
  2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
@ 2011-10-31 10:05                       ` Ian Campbell
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 10:05 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> 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 df2b7f8..62e7fba 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)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 00/13] New event API
  2011-10-28 18:36 [PATCH RFC v2 00/13] New event API Ian Jackson
  2011-10-28 18:36 ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Jackson
@ 2011-10-31 10:11 ` Ian Campbell
  2011-11-07 11:50   ` Roger Pau Monné
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 10:11 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 2011-10-28 at 19:36 +0100, Ian Jackson wrote:
> This is a revised RFC version of my event handling API proposal.
> 
> It consists of 10 rather uninteresting preparatory, stylistic
> and bugfix patches, plus 3 with some meat in:
>   02/13  libxenstore: Provide xs_check_watch
>   12/13  libxl: New API for providing OS events to libxl
>   13/13  libxl: New event generation API
> 
> This series contains an implementation of almost everything, and
> builds apart from the lack of libxl_event_free, but it has not been
> executed at all.

> 
> So at this stage a very detailed code review, particularly of 12 and
> 13 is probably not appropriate.  However, this is hopefully a
> near-final version of the external and internal interfaces so it would
> be worth looking at those.

I reviewed all but #12 and #13 so far and I think they can mostly go in
now, at least in principal. I acked the majority with that in mind.

I suppose the ones which introduce new facilities should/could wait for
the actual users (which I presume are in #12 and #13) which I guess was
your intent but I think #1, #3, #5, #8, #10 and #11 would be obviously
fine right now.

#3 is a bit borderline wrt having a user but I think you wanted
libxl_qmp.c to use it so bashing it in now makes sense?

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 13/13] libxl: New event generation API
  2011-10-28 18:37                         ` [PATCH RFC v2 13/13] libxl: New event generation API Ian Jackson
@ 2011-10-31 11:49                           ` Ian Campbell
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 11:49 UTC (permalink / raw)
  To: Ian Jackson, Jim Fehlig, Dave Scott, Jon Ludlam; +Cc: xen-devel

I've not looked at this yet but CCing a few potential users of this
interface. I've trimmed it to just the public header changes for their
benefit, I'm sure they can find the full thing in the archive if they
are interested in the gorey details.

On Fri, 2011-10-28 at 19:37 +0100, 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          |  306 +++++++++++++++++++++++++++++------------
>  tools/libxl/libxl.h          |   55 ++-------
>  tools/libxl/libxl_event.c    |  182 +++++++++++++++++++++++---
>  tools/libxl/libxl_event.h    |  172 +++++++++++++++++++++++
>  tools/libxl/libxl_internal.c |    6 +
>  tools/libxl/libxl_internal.h |   66 +++++++++
>  tools/libxl/libxl_types.idl  |   35 ++++-
>  tools/libxl/xl_cmdimpl.c     |  261 +++++++++++++++++++++---------------
>  8 files changed, 815 insertions(+), 268 deletions(-)
> 
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index da06ed2..4759c18 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_destroy(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"
> @@ -295,51 +303,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.h b/tools/libxl/libxl_event.h
> index 48c6277..c52addc 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.
> +   */
> +
> +int 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.
> +   */
> +
> 
>  /*======================================================================*/
> 
> diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
> index 62e7fba..202ba89 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_types.idl b/tools/libxl/libxl_types.idl
> index 93fb8cd..53c07ee 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"),
> @@ -374,3 +369,33 @@ libxl_sched_credit = Struct("sched_credit", [
>      ("weight", integer),
>      ("cap", integer),
>      ], destructor_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, c_only=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),
> +                                 ])),
> +           ]))])
> +

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl
  2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
  2011-10-28 18:37                         ` [PATCH RFC v2 13/13] libxl: New event generation API Ian Jackson
@ 2011-10-31 12:15                         ` Ian Campbell
  2011-11-07 10:42                         ` Stefano Stabellini
  2 siblings, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-10-31 12:15 UTC (permalink / raw)
  To: Ian Jackson, Jon Ludlam, Dave Scott, Jim Fehlig; +Cc: xen-devel

Jon/Dave/Jim,

I CC'd you the API bits from 13/13 (as potential users of it) without
realising that there was some here too. Once again I've trimmed this to
just the public headers, see the archives if you want the underlying
bits.

Comments on the suitability for your usecases etc gratefully received.

Ian.

 On Fri, 2011-10-28 at 19:37 +0100, 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    |  704 ++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/libxl_event.h    |  185 +++++++++++
>  tools/libxl/libxl_internal.h |  212 +++++++++++++-
>  6 files changed, 1131 insertions(+), 3 deletions(-)
>  create mode 100644 tools/libxl/libxl_event.c
>  create mode 100644 tools/libxl/libxl_event.h
[...]
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 5d28ff9..da06ed2 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"
> @@ -221,6 +222,9 @@ enum {
>      ERROR_INVAL = -6,
>      ERROR_BADFAIL = -7,
>      ERROR_GUEST_TIMEDOUT = -8,
> +    ERROR_NOT_READY = -9,
> +    ERROR_OSEVENT_REG_FAIL = -10,
> +    ERROR_BUFFERFULL = -11,
>  };
> 
>  #define LIBXL_VERSION 0
> @@ -539,6 +543,8 @@ const char *libxl_xen_script_dir_path(void);
>  const char *libxl_lock_dir_path(void);
>  const char *libxl_run_dir_path(void);
> 
> +#include <libxl_event.h>
> +
>  #endif /* LIBXL_H */
> 
>  /*
> [...]
> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h
> new file mode 100644
> index 0000000..48c6277
> --- /dev/null
> +++ b/tools/libxl/libxl_event.h
> @@ -0,0 +1,185 @@
> +/*
> + * 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).
> +   *
> +   * 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:
> + */

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch
  2011-10-31  9:39     ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Campbell
@ 2011-11-02 16:35       ` Ian Jackson
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-02 16:35 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch"):
> Since setnonblock cannot itself return an error should it always
> preserve errno on behalf of the caller?

Good idea.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-10-31  9:50             ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Campbell
@ 2011-11-02 16:36               ` Ian Jackson
  2011-11-02 19:43                 ` Ian Campbell
  0 siblings, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-11-02 16:36 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> I suspect there isn't much scope for abuse of this capability but would
> a few words of guidance in CODING_STYLE make sense?

I don't think there's anything I feel needs saying.  If you think
people are likely to abuse it in a particular way then do say :-).

Otherwise we can wait and see what results and add stuff to
CODING_STYLE as necessary ?

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 07/13] libxl: internal convenience macros
  2011-10-31  9:53               ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Campbell
@ 2011-11-02 16:37                 ` Ian Jackson
  2011-11-02 19:44                   ` Ian Campbell
  0 siblings, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-11-02 16:37 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 07/13] libxl: internal convenience macros"):
> On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> > +#define GC_INIT(ctx)  libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) }
...
> Is there a massive conversion patch somewhere downseries?

Not yet.  I decided I didn't want to put that on the critical path for
my event handling series, and also of course I didn't want a large
style cleanup patch at the end of my series to keep getting conflicts.

However this is something I have my eye on.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-10-31 10:03                   ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Campbell
@ 2011-11-02 16:38                     ` Ian Jackson
  2011-11-02 19:54                       ` Ian Campbell
  2011-11-28 15:47                     ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-11-02 16:38 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx"):
> On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> > +    const pthread_mutex_t mutex_value = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
...
> > +    memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));
> 
> Is this subtly different to
>        ctx->lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
> in some way I'm missing?

Yes.  PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is formally valid only as
an initialiser, not necessarily as an expression.  I'm not sure that
relevant GCC extensions mean the two are always equivalent.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h
  2011-10-31  9:43       ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Campbell
@ 2011-11-02 17:28         ` Anil Madhavapeddy
  2011-11-03 10:40           ` Christoph Egger
  0 siblings, 1 reply; 52+ messages in thread
From: Anil Madhavapeddy @ 2011-11-02 17:28 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel, Ian Jackson

On 31 Oct 2011, at 09:43, Ian Campbell wrote:

> On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
>> @@ -18,6 +18,14 @@ GPLv2. See the FSF's definition of GPL compatibility:
>> And how this applies to a range of open source licenses:
>>  http://www.gnu.org/licenses/license-list.html
>> 
>> +Additionally, the documentation file tools/libxl/external/bsd-queue.3
>> +has the 4-clause BSD licence.  It is present in the Xen source tree
>> +for reference purposes for people developing Xen.  It is not installed
>> +by "make install" and is bundled in the source only for convenience of
>> +distribution.  We do not intend that we or Xen users or distributors
>> +should make any reference to "features or use" of that manpage.
> 
> Anil pointed to the OpenBSD version of this page which has that clause
> removed. It would simplify things to use their version (of the header
> too for consistency)?  We are probably not comfortable with just
> rescinding the clause ourselves?

If you rescind it yourself, you'll need to go through the FreeBSD CVS history to make sure that there were no other contributors other than Berkeley. OpenBSD already did that in 2002 (and subsequent patches take on the new license, so it doesn't matter).

-anil

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-02 16:36               ` Ian Jackson
@ 2011-11-02 19:43                 ` Ian Campbell
  2011-11-07 10:43                   ` Stefano Stabellini
  0 siblings, 1 reply; 52+ messages in thread
From: Ian Campbell @ 2011-11-02 19:43 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Wed, 2011-11-02 at 12:36 -0400, Ian Jackson wrote:
> Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> > I suspect there isn't much scope for abuse of this capability but would
> > a few words of guidance in CODING_STYLE make sense?
> 
> I don't think there's anything I feel needs saying.  If you think
> people are likely to abuse it in a particular way then do say :-).
> 
> Otherwise we can wait and see what results and add stuff to
> CODING_STYLE as necessary ?

Yes, lets do that.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 07/13] libxl: internal convenience macros
  2011-11-02 16:37                 ` Ian Jackson
@ 2011-11-02 19:44                   ` Ian Campbell
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-11-02 19:44 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Wed, 2011-11-02 at 12:37 -0400, Ian Jackson wrote:
> Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 07/13] libxl: internal convenience macros"):
> > On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> > > +#define GC_INIT(ctx)  libxl__gc gc[1] = { LIBXL_INIT_GC(ctx) }
> ...
> > Is there a massive conversion patch somewhere downseries?
> 
> Not yet.  I decided I didn't want to put that on the critical path for
> my event handling series, and also of course I didn't want a large
> style cleanup patch at the end of my series to keep getting conflicts.
> 
> However this is something I have my eye on.

Great, thanks.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-11-02 16:38                     ` Ian Jackson
@ 2011-11-02 19:54                       ` Ian Campbell
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-11-02 19:54 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Wed, 2011-11-02 at 12:38 -0400, Ian Jackson wrote:
> Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx"):
> > On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> > > +    const pthread_mutex_t mutex_value = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
> ...
> > > +    memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));
> > 
> > Is this subtly different to
> >        ctx->lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
> > in some way I'm missing?
> 
> Yes.  PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is formally valid only as
> an initialiser, not necessarily as an expression.  I'm not sure that
> relevant GCC extensions mean the two are always equivalent.

OK, thanks.

I just had a read of pthread_mutex(3) and I'm surprised how many hoops
one has to jump through to use pthread_mutex_init(). Well, I say
surprised...

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h
  2011-11-02 17:28         ` Anil Madhavapeddy
@ 2011-11-03 10:40           ` Christoph Egger
  0 siblings, 0 replies; 52+ messages in thread
From: Christoph Egger @ 2011-11-03 10:40 UTC (permalink / raw)
  To: Anil Madhavapeddy; +Cc: xen-devel, Ian Jackson, Ian Campbell

On 11/02/11 18:28, Anil Madhavapeddy wrote:
> On 31 Oct 2011, at 09:43, Ian Campbell wrote:
>
>> On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
>>> @@ -18,6 +18,14 @@ GPLv2. See the FSF's definition of GPL compatibility:
>>> And how this applies to a range of open source licenses:
>>>   http://www.gnu.org/licenses/license-list.html
>>>
>>> +Additionally, the documentation file tools/libxl/external/bsd-queue.3
>>> +has the 4-clause BSD licence.  It is present in the Xen source tree
>>> +for reference purposes for people developing Xen.  It is not installed
>>> +by "make install" and is bundled in the source only for convenience of
>>> +distribution.  We do not intend that we or Xen users or distributors
>>> +should make any reference to "features or use" of that manpage.
>>
>> Anil pointed to the OpenBSD version of this page which has that clause
>> removed. It would simplify things to use their version (of the header
>> too for consistency)?  We are probably not comfortable with just
>> rescinding the clause ourselves?
>
> If you rescind it yourself, you'll need to go through the FreeBSD CVS history
 > to make sure that there were no other contributors other than 
Berkeley. OpenBSD
> already did that in 2002 (and subsequent patches take on the new license, so it doesn't matter).

According to cvs history both NetBSD and OpenBSD did that in 2003. Now
it's just about to compare whose content matches most with FreeBSD's
implementation. :)

Christoph

-- 
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Einsteinring 24, 85689 Dornach b. Muenchen
Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl
  2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
  2011-10-28 18:37                         ` [PATCH RFC v2 13/13] libxl: New event generation API Ian Jackson
  2011-10-31 12:15                         ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Campbell
@ 2011-11-07 10:42                         ` Stefano Stabellini
  2011-11-28 15:34                           ` Ian Jackson
  2 siblings, 1 reply; 52+ messages in thread
From: Stefano Stabellini @ 2011-11-07 10:42 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

On Fri, 28 Oct 2011, Ian Jackson wrote:
> + * 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;
> + *      }
> + *   }

It is good that you included an example here but it doesn't follow the
CODING_STYLE

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-02 19:43                 ` Ian Campbell
@ 2011-11-07 10:43                   ` Stefano Stabellini
  2011-11-28 16:40                     ` Ian Jackson
  0 siblings, 1 reply; 52+ messages in thread
From: Stefano Stabellini @ 2011-11-07 10:43 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel, Ian Jackson

On Wed, 2 Nov 2011, Ian Campbell wrote:
> On Wed, 2011-11-02 at 12:36 -0400, Ian Jackson wrote:
> > Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> > > I suspect there isn't much scope for abuse of this capability but would
> > > a few words of guidance in CODING_STYLE make sense?
> > 
> > I don't think there's anything I feel needs saying.  If you think
> > people are likely to abuse it in a particular way then do say :-).
> > 
> > Otherwise we can wait and see what results and add stuff to
> > CODING_STYLE as necessary ?
> 
> Yes, lets do that.
> 

I think it would make sense to add to the CODING_STYLE that variable
declarations shouldn't be mixed with code, unless part of a macro or an
alloca-like construct.
Basically the coding style should stay the same that is now.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 00/13] New event API
  2011-10-31 10:11 ` [PATCH RFC v2 00/13] New event API Ian Campbell
@ 2011-11-07 11:50   ` Roger Pau Monné
  2011-11-22 16:04     ` Ian Jackson
  0 siblings, 1 reply; 52+ messages in thread
From: Roger Pau Monné @ 2011-11-07 11:50 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel, Ian Jackson

I'm sorry to ask such a noobish question... I'm trying to import this
patches into my source tree, but mimport seems to be unable to
correctly sort them (maybe because they seem to be in git format).
What's the best way to import them directly from my mailbox?

Thanks, Roger.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 00/13] New event API
  2011-11-07 11:50   ` Roger Pau Monné
@ 2011-11-22 16:04     ` Ian Jackson
  2011-11-23  9:31       ` Roger Pau Monné
  0 siblings, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-11-22 16:04 UTC (permalink / raw)
  To: Roger Pau Monné; +Cc: xen-devel, Ian Campbell

Roger Pau Monné writes ("Re: [Xen-devel] [PATCH RFC v2 00/13] New event API"):
> I'm sorry to ask such a noobish question... I'm trying to import this
> patches into my source tree, but mimport seems to be unable to
> correctly sort them (maybe because they seem to be in git format).
> What's the best way to import them directly from my mailbox?

I'm afraid I don't know.  With my upstream hat on, for applying
patches, I have an absolutely hideous script.  (Below but don't read
it if you want to keep your lunch.)  With my contributor hat on I
almost always use git.

Ian.


#!/bin/bash
set -e

file=$1

perl -pe <$file >$file.mangled '
        BEGIN { $nl=""; }
        if (m/^\S/ || m/^$/) {
                if (defined $subj) {
                        die "$subj ?" if $subj =~ m/rfc/i;
                        $subj =~ s/\[xen-devel\]//i;
                        $subj =~ s/\[patch[ 0-9a-z,]*\]//i;
                        $subj =~ s/\s+/ /g;
                        $subj =~ s/^\s+//; $subj =~ s/\s+$//;
                        print "Subject: $subj\n";
                        $subj= undef;
                        $nl= "\n";
                }
        }
        if (m/^subject:\s+/i) {
                $subj= $'\'';
        } elsif (defined $subj) {
                $subj .= $_;
        }
        if (m/^$/) {
                print $nl;
                $nl= "";
        }
        $_="" if defined $subj;
        if ($last =~ m/^signed-off-by/i && !m/^signed-off-by/i) {
                print <<END or die $!;
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
END
#Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
#
#Acked-by: Ian Campbell <ian.campbell@citrix.com>
        }
        $last= $_;
'


formail -s hg import - < $file.mangled

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 00/13] New event API
  2011-11-22 16:04     ` Ian Jackson
@ 2011-11-23  9:31       ` Roger Pau Monné
  2011-11-28 17:11         ` Ian Jackson
  0 siblings, 1 reply; 52+ messages in thread
From: Roger Pau Monné @ 2011-11-23  9:31 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Ian Campbell

2011/11/22 Ian Jackson <Ian.Jackson@eu.citrix.com>:
> I'm afraid I don't know.  With my upstream hat on, for applying
> patches, I have an absolutely hideous script.  (Below but don't read
> it if you want to keep your lunch.)  With my contributor hat on I
> almost always use git.

Thanks for the script, I will try to import this series later this
week if I can get my hands on an unused virtualization server (right
now all my available servers are busy). Shouldn't we agree on having
only one repository format? Either git or mercurial is fine for me,
but it will avoid this kind of situations.

Regards, Roger.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl
  2011-11-07 10:42                         ` Stefano Stabellini
@ 2011-11-28 15:34                           ` Ian Jackson
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-28 15:34 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel

Stefano Stabellini writes ("Re: [Xen-devel] [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl"):
> On Fri, 28 Oct 2011, Ian Jackson wrote:
> > + * 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;
> > + *      }
> > + *   }
> 
> It is good that you included an example here but it doesn't follow the
> CODING_STYLE

I guess you mean the inner indent level being 2 and the missing spaces
near "r=".  Fixed.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-10-31 10:03                   ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Campbell
  2011-11-02 16:38                     ` Ian Jackson
@ 2011-11-28 15:47                     ` Ian Jackson
  2011-11-28 15:58                       ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Ian Jackson @ 2011-11-28 15:47 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx"):
> On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> > +    memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));
> 
> Is this subtly different to
>        ctx->lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
> in some way I'm missing?

I have added a comment about this.  (In my own tree; I'll repost the
series shortly.)

> > +    pthread_mutex_t lock; /* protects data structures hanging off the ctx */
> > +      /* always use MUTEX_LOCK and MUTEX_UNLOCK to manipulate this */
> 
> MUTEX is something of an implementation detail (although I admit we are
> unlikely to use anything else), perhaps CTX_(UN)LOCK?

Renamed.

> Perhaps give the variable a less obvious name to help discourage direct
> use?

I think the comment right next to it ought to be sufficient.

> > +#define MUTEX_LOCK do {                                 \
> > +        int mutex_r = pthread_mutex_lock(&CTX->lock);   \
> > +        assert(!mutex_r);                               \
> 
> This assert is to catch EINVAL ("the mutex has not been properly
> initialized") rather than EDEADLK ("the mutex is already locked by the
> calling thread") since we asked for a non-error-checking recursive lock?

Yes.

> Since it is OK to take this lock recursively then it might be as well to
> say so explicitly?
> 
> This is the first lock in libxl so I guess there isn't much of a locking
> hierarchy yet. Are there any particular considerations which a caller
> must make wrt its own locking?

I have added a comment explaining this.  No requirements are imposed
on libxl's caller.  (Other than the reentrancy ones on callbacks.)

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx
  2011-11-28 15:47                     ` Ian Jackson
@ 2011-11-28 15:58                       ` Ian Jackson
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-28 15:58 UTC (permalink / raw)
  To: Ian Campbell, xen-devel

Ian Jackson writes ("Re: [Xen-devel] [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx"):
> Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx"):
> > Since it is OK to take this lock recursively then it might be as well to
> > say so explicitly?
> > 
> > This is the first lock in libxl so I guess there isn't much of a locking
> > hierarchy yet. Are there any particular considerations which a caller
> > must make wrt its own locking?
> 
> I have added a comment explaining this.  No requirements are imposed
> on libxl's caller.  (Other than the reentrancy ones on callbacks.)

In fact this turns out not to be true.  I will document the
restrictions.  Good question BTW.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-07 10:43                   ` Stefano Stabellini
@ 2011-11-28 16:40                     ` Ian Jackson
  2011-11-29 10:45                       ` Ian Campbell
  2011-11-29 17:47                       ` Stefano Stabellini
  0 siblings, 2 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-28 16:40 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Ian Campbell

Stefano Stabellini writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> I think it would make sense to add to the CODING_STYLE that variable
> declarations shouldn't be mixed with code, unless part of a macro or an
> alloca-like construct.

I think this is a silly rule.  In my proposed commit message I
advanced three reasons for allowing declaration after statement:

> >  * 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.

Of these the first two improvements would be banned by your proposed
coding style rule.

I don't understand what the harm is in allowing declarations, with
initialisation, freely mixed with code.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 00/13] New event API
  2011-11-23  9:31       ` Roger Pau Monné
@ 2011-11-28 17:11         ` Ian Jackson
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-28 17:11 UTC (permalink / raw)
  To: Roger Pau Monné; +Cc: xen-devel, Ian Campbell

Roger Pau Monné writes ("Re: [Xen-devel] [PATCH RFC v2 00/13] New event API"):
> 2011/11/22 Ian Jackson <Ian.Jackson@eu.citrix.com>:
> > I'm afraid I don't know.  With my upstream hat on, for applying
> > patches, I have an absolutely hideous script.  (Below but don't read
> > it if you want to keep your lunch.)  With my contributor hat on I
> > almost always use git.
> 
> Thanks for the script, I will try to import this series later this
> week if I can get my hands on an unused virtualization server (right
> now all my available servers are busy). Shouldn't we agree on having
> only one repository format? Either git or mercurial is fine for me,
> but it will avoid this kind of situations.

Well, with my contributor hat on you can pry my git out of my cold
dead fingers.

With my upstream hat on, I'm happy to accept patches generated by any
reasonable vcs (or none).  But I don't think we have a consensus to
change xen-unstable to git.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-28 16:40                     ` Ian Jackson
@ 2011-11-29 10:45                       ` Ian Campbell
  2011-11-29 10:52                         ` Ian Campbell
  2011-11-29 14:04                         ` Ian Jackson
  2011-11-29 17:47                       ` Stefano Stabellini
  1 sibling, 2 replies; 52+ messages in thread
From: Ian Campbell @ 2011-11-29 10:45 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Stefano Stabellini

On Mon, 2011-11-28 at 16:40 +0000, Ian Jackson wrote:
> Stefano Stabellini writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> > I think it would make sense to add to the CODING_STYLE that variable
> > declarations shouldn't be mixed with code, unless part of a macro or an
> > alloca-like construct.
> 
> I think this is a silly rule.  In my proposed commit message I
> advanced three reasons for allowing declaration after statement:
> 
> > >  * 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.
> 
> Of these the first two improvements would be banned by your proposed
> coding style rule.
> 
> I don't understand what the harm is in allowing declarations, with
> initialisation, freely mixed with code.

Variable declarations should either be at the top of the function or
immediately before / as part of the block which uses them. e.g. this is
unhelpful:

void a_func(void)
{
	/* a bunch of code; */

	int bar;

	/* a bunch more code not using bar */

	bar = get_me_a_bar();

	/* use bar lots */
}

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-29 10:45                       ` Ian Campbell
@ 2011-11-29 10:52                         ` Ian Campbell
  2011-11-29 14:04                         ` Ian Jackson
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Campbell @ 2011-11-29 10:52 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Stefano Stabellini

On Tue, 2011-11-29 at 10:45 +0000, Ian Campbell wrote:

> Variable declarations should either be at the top of the function or
> immediately before / as part of the block which uses them. e.g. this is
> unhelpful:

This isn't an objection to the patch BTW, I'm happy with your
reasoning...

> 
> void a_func(void)
> {
> 	/* a bunch of code; */
> 
> 	int bar;
> 
> 	/* a bunch more code not using bar */
> 
> 	bar = get_me_a_bar();
> 
> 	/* use bar lots */
> }
> 
> Ian.
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-29 10:45                       ` Ian Campbell
  2011-11-29 10:52                         ` Ian Campbell
@ 2011-11-29 14:04                         ` Ian Jackson
  1 sibling, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-29 14:04 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel, Ian Jackson, Stefano Stabellini

Ian Campbell writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after	statement"):
> Variable declarations should either be at the top of the function or
> immediately before / as part of the block which uses them. e.g. this is
> unhelpful:

I agree..

> void a_func(void)
> {
> 	/* a bunch of code; */
> 
> 	int bar;
> 
> 	/* a bunch more code not using bar */
> 
> 	bar = get_me_a_bar();
> 
> 	/* use bar lots */
> }

Yes, but would anyone really write that ?  I think the argument is
about this:

 	/* a bunch of code; */
 
 	int bar = get_me_a_bar();
 
 	/* use bar lots */

I think this is fine and I think Stefano objects.

How about:

  Declarations of automatic variables should either be at the start of
  the relevant function (or block), or as late as reasonable; in the
  latter case they should be initialised in the declaration if
  possible.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-28 16:40                     ` Ian Jackson
  2011-11-29 10:45                       ` Ian Campbell
@ 2011-11-29 17:47                       ` Stefano Stabellini
  2011-11-29 18:06                         ` Ian Jackson
  1 sibling, 1 reply; 52+ messages in thread
From: Stefano Stabellini @ 2011-11-29 17:47 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Ian Campbell, Stefano Stabellini

On Mon, 28 Nov 2011, Ian Jackson wrote:
> Stefano Stabellini writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> > I think it would make sense to add to the CODING_STYLE that variable
> > declarations shouldn't be mixed with code, unless part of a macro or an
> > alloca-like construct.
> 
> I think this is a silly rule.  In my proposed commit message I
> advanced three reasons for allowing declaration after statement:
> 
> > >  * 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.
> 
> Of these the first two improvements would be banned by your proposed
> coding style rule.

Only the first would be banned, I am OK with making an exception for
alloca constructs and macros.


> I don't understand what the harm is in allowing declarations, with
> initialisation, freely mixed with code.


It makes the code harder to read;
it makes it more difficult to rearrange local variables in the future;
it makes it more difficult to see how much stack your function is using;
it makes it more difficult to realize if you can reduce the amount of
local variables you are using.

And it violates the current coding style.

I think that declaring variables at the beginning of the function is a
good programming practice in any language.

The three most important C codebases in the Xen project are: Linux,
Qemu and Xen. None of these allow mixing declarations and code, for a
good reason. I don't think libxl should have a different code style in
this regard, it would just be confusing.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH RFC v2 06/13] libxl: permit declaration after statement
  2011-11-29 17:47                       ` Stefano Stabellini
@ 2011-11-29 18:06                         ` Ian Jackson
  0 siblings, 0 replies; 52+ messages in thread
From: Ian Jackson @ 2011-11-29 18:06 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Ian Campbell

Stefano Stabellini writes ("Re: [Xen-devel] [PATCH RFC v2 06/13] libxl: permit declaration after statement"):
> On Mon, 28 Nov 2011, Ian Jackson wrote:
> > I don't understand what the harm is in allowing declarations, with
> > initialisation, freely mixed with code.
> 
> 
> It makes the code harder to read;

Naturally I disagree, but this is a matter of subjective taste as far
as I can tell, unless you have something specific to point to.

> it makes it more difficult to rearrange local variables in the future;

I'm not sure what you mean by "rearrange local variables".  The style
where variables are declared only at the top of the file tends to
result in long lists of local variables in declaration statements at
the top of functions.  Those long lists make editing the function
somewhat more complex.

Declaring variables in the same statement as they are initialised
naturally makes "rearranging" them trivial.

> it makes it more difficult to see how much stack your function is using;

This is not relevant in libxl unless the objects are truly huge (in
which case they shouldn't be on the stack at all).

> it makes it more difficult to realize if you can reduce the amount of
> local variables you are using.

There is no benefit in trying to "reduce the amount of local
variables" in userland C code compiled with a reasonable optimising
compiler.  The compiler will be able to do the same liveness analysis
either way.

> And it violates the current coding style.

This is not an argument against changing the coding style.

> I think that declaring variables at the beginning of the function is a
> good programming practice in any language.

I think that initialising variables at the time they are declared,
where reasonable, is good programming practice in any language.

> The three most important C codebases in the Xen project are: Linux,
> Qemu and Xen. None of these allow mixing declarations and code, for a
> good reason. I don't think libxl should have a different code style in
> this regard, it would just be confusing.

I don't see this as a particularly relevant consideration.  There are
lots of other ways our coding style differs from (say) Linux.  Any
competent C programmer will be familiar with both styles.

Ian.

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2011-11-29 18:06 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-28 18:36 [PATCH RFC v2 00/13] New event API Ian Jackson
2011-10-28 18:36 ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Jackson
2011-10-28 18:37   ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Jackson
2011-10-28 18:37     ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Jackson
2011-10-28 18:37       ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Jackson
2011-10-28 18:37         ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Jackson
2011-10-28 18:37           ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Jackson
2011-10-28 18:37             ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Jackson
2011-10-28 18:37               ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Jackson
2011-10-28 18:37                 ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Jackson
2011-10-28 18:37                   ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Jackson
2011-10-28 18:37                     ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Jackson
2011-10-28 18:37                       ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Jackson
2011-10-28 18:37                         ` [PATCH RFC v2 13/13] libxl: New event generation API Ian Jackson
2011-10-31 11:49                           ` Ian Campbell
2011-10-31 12:15                         ` [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl Ian Campbell
2011-11-07 10:42                         ` Stefano Stabellini
2011-11-28 15:34                           ` Ian Jackson
2011-10-31 10:05                       ` [PATCH RFC v2 11/13] libxl: make libxl__free_all idempotent Ian Campbell
2011-10-31 10:04                     ` [PATCH RFC v2 10/13] libxl: make libxl__[v]log const-correct Ian Campbell
2011-10-31 10:03                   ` [PATCH RFC v2 09/13] libxl: introduce lock in libxl_ctx Ian Campbell
2011-11-02 16:38                     ` Ian Jackson
2011-11-02 19:54                       ` Ian Campbell
2011-11-28 15:47                     ` Ian Jackson
2011-11-28 15:58                       ` Ian Jackson
2011-10-31  9:55                 ` [PATCH RFC v2 08/13] libxl: Rationalise #includes Ian Campbell
2011-10-31  9:53               ` [PATCH RFC v2 07/13] libxl: internal convenience macros Ian Campbell
2011-11-02 16:37                 ` Ian Jackson
2011-11-02 19:44                   ` Ian Campbell
2011-10-31  9:50             ` [PATCH RFC v2 06/13] libxl: permit declaration after statement Ian Campbell
2011-11-02 16:36               ` Ian Jackson
2011-11-02 19:43                 ` Ian Campbell
2011-11-07 10:43                   ` Stefano Stabellini
2011-11-28 16:40                     ` Ian Jackson
2011-11-29 10:45                       ` Ian Campbell
2011-11-29 10:52                         ` Ian Campbell
2011-11-29 14:04                         ` Ian Jackson
2011-11-29 17:47                       ` Stefano Stabellini
2011-11-29 18:06                         ` Ian Jackson
2011-10-31  9:47           ` [PATCH RFC v2 05/13] libxl: idl: Provide struct and union tags Ian Campbell
2011-10-31  9:46         ` [PATCH RFC v2 04/13] libxl: idl: support new "c_only" type attribute Ian Campbell
2011-10-31  9:43       ` [PATCH RFC v2 03/13] libxl: Provide a version of bsd's queue.h as _libxl_list.h Ian Campbell
2011-11-02 17:28         ` Anil Madhavapeddy
2011-11-03 10:40           ` Christoph Egger
2011-10-31  9:39     ` [PATCH RFC v2 02/13] libxenstore: Provide xs_check_watch Ian Campbell
2011-11-02 16:35       ` Ian Jackson
2011-10-31  9:34   ` [PATCH RFC v2 01/13] libxl: Make libxl__xs_* more const-correct Ian Campbell
2011-10-31 10:11 ` [PATCH RFC v2 00/13] New event API Ian Campbell
2011-11-07 11:50   ` Roger Pau Monné
2011-11-22 16:04     ` Ian Jackson
2011-11-23  9:31       ` Roger Pau Monné
2011-11-28 17:11         ` Ian Jackson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.