[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 14/15] libxl: New API for providing OS events to libxl



On Mon, 5 Dec 2011, Ian Jackson wrote:
> We provide a new set of functions and related structures
>   libxl_osevent_*
> which are to be used by event-driven applications to receive
> information from libxl about which fds libxl is interested in, and
> what timeouts libxl is waiting for, and to pass back to libxl
> information about which fds are readable/writeable etc., and which
> timeouts have occurred.  Ie, low-level events.
> 
> In this patch, this new machinery is still all unused.  Callers will
> appear in the next patch in the series, which introduces a new API for
> applications to receive high-level events about actual domains etc.
> 
> Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> ---
>  tools/libxl/Makefile         |    2 +-
>  tools/libxl/libxl.c          |   25 ++
>  tools/libxl/libxl.h          |    6 +
>  tools/libxl/libxl_event.c    |  711 
> ++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/libxl_event.h    |  199 ++++++++++++
>  tools/libxl/libxl_internal.h |  216 +++++++++++++-
>  6 files changed, 1155 insertions(+), 4 deletions(-)
>  create mode 100644 tools/libxl/libxl_event.c
>  create mode 100644 tools/libxl/libxl_event.h
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index 4e0f3fb..3d575b8 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -38,7 +38,7 @@ LIBXL_LIBS += -lyajl
>  LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
>                         libxl_dom.o libxl_exec.o libxl_xshelp.o 
> libxl_device.o \
>                         libxl_internal.o libxl_utils.o libxl_uuid.o 
> libxl_json.o \
> -                       libxl_qmp.o $(LIBXL_OBJS-y)
> +                       libxl_qmp.o libxl_event.o $(LIBXL_OBJS-y)
>  LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
> 
>  $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) 
> $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl)
> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 3a8cfe3..58f280c 100644
> --- a/tools/libxl/libxl.c
> +++ b/tools/libxl/libxl.c
> @@ -60,6 +60,16 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version,
>       * only as an initialiser, not as an expression. */
>      memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));
> 
> +    ctx->osevent_hooks = 0;
> +
> +    ctx->fd_beforepolled = 0;
> +    LIBXL_LIST_INIT(&ctx->efds);
> +    LIBXL_TAILQ_INIT(&ctx->etimes);
> +
> +    ctx->watch_slots = 0;
> +    LIBXL_SLIST_INIT(&ctx->watch_freeslots);
> +    libxl__ev_fd_init(&ctx->watch_efd);
> +
>      if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) {
>          LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon 
> running?\n"
>                       "failed to stat %s", XENSTORE_PID_FILE);
> @@ -89,10 +99,25 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version,
> 
>  int libxl_ctx_free(libxl_ctx *ctx)
>  {
> +    int i;
> +    GC_INIT(ctx);
> +
>      if (!ctx) return 0;
> +
> +    for (i = 0; i < ctx->watch_nslots; i++)
> +        assert(!libxl__watch_slot_contents(gc, i));
> +    libxl__ev_fd_deregister(gc, &ctx->watch_efd);
> +
> +    assert(LIBXL_LIST_EMPTY(&ctx->efds));
> +    assert(LIBXL_TAILQ_EMPTY(&ctx->etimes));
> +
>      if (ctx->xch) xc_interface_close(ctx->xch);
>      libxl_version_info_dispose(&ctx->version_info);
>      if (ctx->xsh) xs_daemon_close(ctx->xsh);
> +
> +    free(ctx->fd_beforepolled);
> +    free(ctx->watch_slots);
> +
>      return 0;
>  }
> 
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 289dc85..654a5b0 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -137,6 +137,7 @@
>  #include <xen/sysctl.h>
> 
>  #include <libxl_uuid.h>
> +#include <_libxl_list.h>
> 
>  typedef uint8_t libxl_mac[6];
>  #define LIBXL_MAC_FMT "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
> @@ -222,6 +223,9 @@ enum {
>      ERROR_BADFAIL = -7,
>      ERROR_GUEST_TIMEDOUT = -8,
>      ERROR_TIMEDOUT = -9,
> +    ERROR_NOT_READY = -10,
> +    ERROR_OSEVENT_REG_FAIL = -11,
> +    ERROR_BUFFERFULL = -12,
>  };
> 
>  #define LIBXL_VERSION 0
> @@ -635,6 +639,8 @@ const char *libxl_lock_dir_path(void);
>  const char *libxl_run_dir_path(void);
>  const char *libxl_xenpaging_dir_path(void);
> 
> +#include <libxl_event.h>
> +
>  #endif /* LIBXL_H */
> 
>  /*
> diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c
> new file mode 100644
> index 0000000..8d4dbf6
> --- /dev/null
> +++ b/tools/libxl/libxl_event.c
> @@ -0,0 +1,711 @@
> +/*
> + * Copyright (C) 2011      Citrix Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +/*
> + * Internal event machinery for use by other parts of libxl
> + */
> +
> +#include <poll.h>
> +
> +#include "libxl_internal.h"
> +
> +/*
> + * The counter osevent_in_hook is used to ensure that the application
> + * honours the reentrancy restriction documented in libxl_event.h.
> + *
> + * The application's registration hooks should be called ONLY via
> + * these macros, with the ctx locked.  Likewise all the "occurred"
> + * entrypoints from the application should assert(!in_hook);
> + */
> +#define OSEVENT_HOOK_INTERN(defval, hookname, ...)                      \
> +    (CTX->osevent_hooks                                                 \
> +     ? (CTX->osevent_in_hook++,                                         \
> +        CTX->osevent_hooks->hookname(CTX->osevent_user, __VA_ARGS__),   \
> +        CTX->osevent_in_hook--)                                         \
> +     : defval)
> +
> +#define OSEVENT_HOOK(hookname,...)                      \
> +    OSEVENT_HOOK_INTERN(0, hookname, __VA_ARGS__)
> +
> +#define OSEVENT_HOOK_VOID(hookname,...)                 \
> +    OSEVENT_HOOK_INTERN((void)0, hookname, __VA_ARGS__)

Is there any reasons why we cannot use static inline functions here?


> +/*
> + * fd events
> + */
> +
> +int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev,
> +                          libxl__ev_fd_callback *func,
> +                          int fd, short events) {
> +    int rc;
> +
> +    assert(fd >= 0);
> +
> +    CTX_LOCK;
> +
> +    rc = OSEVENT_HOOK(fd_register, fd, &ev->for_app_reg, events, ev);
> +    if (rc) goto out;
> +
> +    LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry);
> +
> +    ev->fd = fd;
> +    ev->events = events;
> +    ev->in_beforepolled = -1;
> +    ev->func = func;
> +
> +    rc = 0;
> +
> + out:
> +    CTX_UNLOCK;
> +    return rc;
> +}
> +
> +int libxl__ev_fd_modify(libxl__gc *gc, libxl__ev_fd *ev, short events) {
> +    int rc;
> +
> +    CTX_LOCK;
> +    assert(libxl__ev_fd_isregistered(ev));
> +
> +    rc = OSEVENT_HOOK(fd_modify, ev->fd, &ev->for_app_reg, events);
> +    if (rc) goto out;
> +
> +    ev->events = events;
> +
> +    rc = 0;
> + out:
> +    CTX_UNLOCK;
> +    return rc;
> +}
> +
> +void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev) {
> +    CTX_LOCK;
> +
> +    if (!libxl__ev_fd_isregistered(ev))
> +        goto out;
> +
> +    OSEVENT_HOOK_VOID(fd_deregister, ev->fd, ev->for_app_reg);
> +    LIBXL_LIST_REMOVE(ev, entry);
> +    ev->fd = -1;
> +
> +    if (ev->in_beforepolled >= 0 &&
> +        ev->in_beforepolled < CTX->fd_beforepolled_used)
> +        /* remove stale reference */
> +        CTX->fd_beforepolled[ev->in_beforepolled] = NULL;
> +
> + out:
> +    CTX_UNLOCK;
> +}
> +
> +/*
> + * timeouts
> + */
> +
> +
> +int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r) {
> +    int rc = gettimeofday(now_r, 0);
> +    if (rc) {
> +        LIBXL__LOG_ERRNO(CTX, LIBXL__LOG_ERROR, "gettimeofday failed");
> +        return ERROR_FAIL;
> +    }
> +    return 0;
> +}
> +
> +static int time_rel_to_abs(libxl__gc *gc, int ms, struct timeval *abs_out) {
> +    int rc;
> +    struct timeval additional = {
> +        .tv_sec = ms / 1000,
> +        .tv_usec = (ms % 1000) * 1000
> +    };
> +    struct timeval now;
> +
> +    rc = libxl__gettimeofday(gc, &now);
> +    if (rc) return rc;
> +
> +    timeradd(&now, &additional, abs_out);
> +    return 0;
> +}
> +
> +static void time_insert_finite(libxl__gc *gc, libxl__ev_time *ev) {
> +    libxl__ev_time *evsearch;
> +    LIBXL_TAILQ_INSERT_SORTED(&CTX->etimes, entry, ev, evsearch, ,
> +                              timercmp(&ev->abs, &evsearch->abs, >));
> +    ev->infinite = 0;
> +}
> +
> +static int time_register_finite(libxl__gc *gc, libxl__ev_time *ev,
> +                                struct timeval abs) {
> +    int rc;
> +
> +    rc = OSEVENT_HOOK(timeout_register, &ev->for_app_reg, abs, ev);
> +    if (rc) return rc;
> +
> +    ev->infinite = 0;
> +    ev->abs = abs;
> +    time_insert_finite(gc, ev);
> +
> +    return 0;
> +}
> +
> +static void time_deregister(libxl__gc *gc, libxl__ev_time *ev) {
> +    if (!ev->infinite) {
> +        OSEVENT_HOOK_VOID(timeout_deregister, &ev->for_app_reg);
> +        LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
> +    }
> +}
> +
> +
> +int libxl__ev_time_register_abs(libxl__gc *gc, libxl__ev_time *ev,
> +                                libxl__ev_time_callback *func,
> +                                struct timeval abs) {
> +    int rc;
> +
> +    CTX_LOCK;
> +
> +    rc = time_register_finite(gc, ev, abs);
> +    if (rc) goto out;
> +
> +    ev->func = func;
> +
> +    rc = 0;
> + out:
> +    CTX_UNLOCK;
> +    return rc;
> +}
> +
> +
> +int libxl__ev_time_register_rel(libxl__gc *gc, libxl__ev_time *ev,
> +                                libxl__ev_time_callback *func,
> +                                int milliseconds /* as for poll(2) */) {
> +    struct timeval abs;
> +    int rc;
> +
> +    CTX_LOCK;
> +
> +    if (milliseconds < 0) {
> +        ev->infinite = 1;
> +    } else {
> +        rc = time_rel_to_abs(gc, milliseconds, &abs);
> +        if (rc) goto out;
> +
> +        rc = time_register_finite(gc, ev, abs);
> +        if (rc) goto out;
> +    }
> +
> +    ev->func = func;
> +    rc = 0;
> +
> + out:
> +    CTX_UNLOCK;
> +    return 0;
> +}
> +
> +int libxl__ev_time_modify_abs(libxl__gc *gc, libxl__ev_time *ev,
> +                              struct timeval abs) {
> +    int rc;
> +
> +    CTX_LOCK;
> +
> +    assert(libxl__ev_time_isregistered(ev));
> +
> +    if (ev->infinite) {
> +        rc = time_register_finite(gc, ev, abs);
> +        if (rc) goto out;
> +    } else {
> +        rc = OSEVENT_HOOK(timeout_modify, &ev->for_app_reg, abs);
> +        if (rc) goto out;
> +
> +        LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
> +        ev->abs = abs;
> +        time_insert_finite(gc, ev);
> +    }
> +
> +    rc = 0;
> + out:
> +    CTX_UNLOCK;
> +    return rc;
> +}
> +
> +int libxl__ev_time_modify_rel(libxl__gc *gc, libxl__ev_time *ev,
> +                              int milliseconds) {
> +    struct timeval abs;
> +    int rc;
> +
> +    CTX_LOCK;
> +
> +    assert(libxl__ev_time_isregistered(ev));
> +
> +    if (milliseconds < 0) {
> +        time_deregister(gc, ev);
> +        ev->infinite = 1;
> +        rc = 0;
> +        goto out;
> +    }
> +
> +    rc = time_rel_to_abs(gc, milliseconds, &abs);
> +    if (rc) goto out;
> +
> +    rc = libxl__ev_time_modify_abs(gc, ev, abs);
> +    if (rc) goto out;
> +
> +    rc = 0;
> + out:
> +    CTX_UNLOCK;
> +    return 0;
> +}
> +
> +void libxl__ev_time_deregister(libxl__gc *gc, libxl__ev_time *ev) {
> +    CTX_LOCK;
> +
> +    if (!libxl__ev_time_isregistered(ev))
> +        goto out;
> +
> +    time_deregister(gc, ev);
> +    ev->func = 0;
> +
> + out:
> +    CTX_UNLOCK;
> +    return;
> +}
> +
> +
> +/*
> + * xenstore watches
> + */
> +
> +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum) {
> +    libxl__ev_watch_slot *slot = &CTX->watch_slots[slotnum];
> +    libxl__ev_watch_slot *slotcontents = LIBXL_SLIST_NEXT(slot, empty);
> +
> +    if (slotcontents == NULL ||
> +        ((uintptr_t)slotcontents >= (uintptr_t)CTX->watch_slots &&
> +         (uintptr_t)slotcontents < (uintptr_t)(CTX->watch_slots +
> +                                               CTX->watch_nslots)))
> +        /* An empty slot has either a NULL pointer (end of the
> +         * free list), or a pointer to another entry in the array.
> +         * So we can do a bounds check to distinguish empty from
> +         * full slots.
> +         */
> +        /* We need to do the comparisons as uintptr_t because
> +         * comparing pointers which are not in the same object is
> +         * undefined behaviour; if the compiler managed to figure
> +         * out that watch_slots[0..watch_nslots-1] is all of the
> +         * whole array object it could prove that the above bounds
> +         * check was always true if it was legal, and remove it!
> +         *
> +         * uintptr_t because even on a machine with signed
> +         * pointers, objects do not cross zero; whereas on
> +         * machines with unsigned pointers, they may cross
> +         * 0x8bazillion.
> +         */
> +        return NULL;
> +
> +        /* see comment near libxl__ev_watch_slot definition */
> +    return (void*)slotcontents;
> +}
> +
> +static void watchfd_callback(libxl__gc *gc, libxl__ev_fd *ev,
> +                             int fd, short events, short revents) {
> +    for (;;) {
> +        char **event = xs_check_watch(CTX->xsh);
> +        if (!event) {
> +            if (errno == EAGAIN) break;
> +            if (errno == EINTR) continue;
> +            LIBXL__EVENT_DISASTER(gc, "cannot check/read watches", errno, 0);
> +            return;
> +        }
> +
> +        const char *epath = event[0];
> +        const char *token = event[1];
> +        int slotnum;
> +        uint32_t counterval;

OK, this is the last time I am going to point this out, but epath,
token, etc, should be declared above, at the beginning of the block.


> +        int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval);
> +        if (rc != 2) {
> +            LIBXL__LOG(CTX, LIBXL__LOG_ERROR,
> +                       "watch epath=%s token=%s: failed to parse token",
> +                       epath, token);
> +            /* oh well */
> +            goto ignore;
> +        }
> +        if (slotnum < 0 || slotnum >= CTX->watch_nslots) {
> +            /* perhaps in the future we will make the watchslots array 
> shrink */
> +            LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, "watch epath=%s token=%s:"
> +                       " slotnum %d out of range [0,%d>",
> +                       epath, token, slotnum, CTX->watch_nslots);
> +            goto ignore;
> +        }
> +
> +        libxl__ev_xswatch *w = libxl__watch_slot_contents(gc, slotnum);
> +
> +        if (!w) {
> +            LIBXL__LOG(CTX, LIBXL__LOG_DEBUG,
> +                       "watch epath=%s token=%s: empty slot",
> +                       epath, token);
> +            goto ignore;
> +        }
> +
> +        if (w->counterval != counterval) {
> +            LIBXL__LOG(CTX, LIBXL__LOG_DEBUG,
> +                       "watch epath=%s token=%s: counter != %"PRIx32,
> +                       epath, token, w->counterval);
> +            goto ignore;
> +        }
> +
> +        /* Now it's possible, though unlikely, that this was an event
> +         * from a previous use of the same slot with the same counterval.
> +         *
> +         * In that case either:
> +         *  - the event path is a child of the watch path, in
> +         *    which case this watch would really have generated this
> +         *    event if it had been registered soon enough and we are
> +         *    OK to give this possibly-spurious event to the caller; or
> +         * - it is not, in which case we must suppress it as the
> +         *   caller should not see events for unrelated paths.
> +         *
> +         * See also docs/misc/xenstore.txt.
> +         */
> +        size_t epathlen = strlen(epath);
> +        size_t wpathlen = strlen(w->path);
> +        if (epathlen < wpathlen ||
> +            memcmp(epath, w->path, wpathlen) ||
> +            (epathlen > wpathlen && epath[wpathlen] != '/')) {
> +            LIBXL__LOG(CTX, LIBXL__LOG_DEBUG,
> +                       "watch epath=%s token=%s: not child of wpath=%s",
> +                       epath, token, w->path);
> +            goto ignore;
> +        }
> +
> +        /* At last, we have checked everything! */
> +        LIBXL__LOG(CTX, LIBXL__LOG_DEBUG,
> +                   "watch event: epath=%s token=%s wpath=%s w=%p",
> +                   epath, token, w->path, w);
> +        w->callback(gc, w, w->path, epath);
> +
> +    ignore:
> +        free(event);
> +    }
> +}
> +
> +static char *watch_token(libxl__gc *gc, int slotnum, uint32_t counterval) {
> +    return libxl__sprintf(gc, "%d/%"PRIx32, slotnum, counterval);
> +}
> +
> +int libxl__ev_xswatch_register(libxl__gc *gc, libxl__ev_xswatch *w,
> +                               libxl__ev_xswatch_callback *func,
> +                               const char *path /* copied */) {
> +    libxl__ev_watch_slot *use = NULL;
> +    char *path_copy = NULL;
> +    int rc;
> +
> +    CTX_LOCK;
> +
> +    if (!libxl__ev_fd_isregistered(&CTX->watch_efd)) {
> +        rc = libxl__ev_fd_register(gc, &CTX->watch_efd, watchfd_callback,
> +                                   xs_fileno(CTX->xsh), POLLIN);
> +        if (rc) goto out_rc;
> +    }
> +
> +    if (LIBXL_SLIST_EMPTY(&CTX->watch_freeslots)) {
> +        /* Free list is empty so there is not in fact a linked
> +         * free list in the array and we can safely realloc it */
> +        int newarraysize = (CTX->watch_nslots + 1) << 2;
> +        int i;
> +        libxl__ev_watch_slot *newarray =
> +            realloc(CTX->watch_slots, sizeof(*newarray) * newarraysize);
> +        if (!newarray) goto out_nomem;
> +        for (i=CTX->watch_nslots; i<newarraysize; i++)

does not follow the CODING_STYLE, it should be

           for (i = CTX->watch_nslots; i < newarraysize; i++)


> +            LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots,
> +                                    &newarray[i], empty);
> +        CTX->watch_slots = newarray;
> +        CTX->watch_nslots = newarraysize;
> +    }

would it make sense to move this code in its own allocate_watch_slots
function?


> +    use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots);
> +    assert(use);
> +    LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty);
> +
> +    path_copy = strdup(path);
> +    if (!path_copy) goto out_nomem;
> +
> +    int slotnum = use - CTX->watch_slots;
> +    w->counterval = CTX->watch_counter++;
> +
> +    if (!xs_watch(CTX->xsh, path, watch_token(gc, slotnum, w->counterval))) {
> +        LIBXL__LOG_ERRNOVAL(CTX, LIBXL__LOG_ERROR, errno,
> +                            "create watch for path %s", path);
> +        rc = ERROR_FAIL;
> +        goto out_rc;
> +    }
> +
> +    w->slotnum = slotnum;
> +    w->path = path_copy;
> +    w->callback = func;
> +    /* we look a bit behind the curtain of LIBXL_SLIST, to explictly
> +     * assign to the pointer that's the next link.  See the comment
> +     * by the definitionn of libxl__ev_watch_slot */
> +    use->empty.sle_next = (void*)w;
> +
> +    CTX_UNLOCK;
> +    return 0;
> +
> + out_nomem:
> +    rc = ERROR_NOMEM;
> + out_rc:
> +    if (use)
> +        LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, use, empty);
> +
> +    free(w->path);
> +    w->path = NULL;
> +
> +    CTX_UNLOCK;
> +}
> +
> +/*
> + * osevent poll
> + */
> +
> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
> +                             struct pollfd *fds, int *timeout_upd,
> +                             struct timeval now) {
> +    libxl__ev_fd *efd;
> +    int i;
> +
> +    /*
> +     * In order to be able to efficiently find the libxl__ev_fd
> +     * for a struct poll during _afterpoll, we maintain a shadow
> +     * data structure in CTX->fd_beforepolled: each slot in
> +     * the fds array corresponds to a slot in fd_beforepolled.
> +     */
> +
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +
> +    if (*nfds_io) {
> +        /*
> +         * As an optimisation, we don't touch fd_beforepolled_used
> +         * if *nfds_io is zero on entry, since in that case the
> +         * caller just wanted to know how big an array to give us.
> +         *
> +         * If !*nfds_io, the unconditional parts below are guaranteed
> +         * not to mess with fd_beforepolled... or any in_beforepolled.
> +         */
> +
> +        /* Remove all the old references into beforepolled */
> +        for (i = 0; i < CTX->fd_beforepolled_used; i++) {
> +            efd = CTX->fd_beforepolled[i];
> +            if (efd) {
> +                assert(efd->in_beforepolled == i);
> +                efd->in_beforepolled = -1;
> +                CTX->fd_beforepolled[i] = NULL;
> +            }
> +        }
> +        CTX->fd_beforepolled_used = 0;
> +
> +        /* make sure our array is as big as *nfds_io */
> +        if (CTX->fd_beforepolled_allocd < *nfds_io) {
> +            assert(*nfds_io < INT_MAX / sizeof(libxl__ev_fd*) / 2);
> +            libxl__ev_fd **newarray =
> +                realloc(CTX->fd_beforepolled, sizeof(*newarray) * *nfds_io);
> +            if (!newarray)
> +                return ERROR_NOMEM;
> +            CTX->fd_beforepolled = newarray;
> +            CTX->fd_beforepolled_allocd = *nfds_io;
> +        }
> +    }
> +
> +    int used = 0;
> +    LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) {
> +        if (used < *nfds_io) {
> +            fds[used].fd = efd->fd;
> +            fds[used].events = efd->events;
> +            fds[used].revents = 0;
> +            CTX->fd_beforepolled[used] = efd;
> +            efd->in_beforepolled = used;
> +        }
> +        used++;
> +    }
> +    int rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL;
> +
> +    if (*nfds_io) {
> +        CTX->fd_beforepolled_used = used;
> +    }
> +
> +    *nfds_io = used;
> +
> +    libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
> +    if (etime) {
> +        int our_timeout;
> +        struct timeval rel;
> +        static struct timeval zero;
> +
> +        timersub(&etime->abs, &now, &rel);
> +
> +        if (timercmp(&rel, &zero, <)) {
> +            our_timeout = 0;
> +        } else if (rel.tv_sec >= 2000000) {
> +            our_timeout = 2000000000;
> +        } else {
> +            our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000;
> +        }
> +        if (*timeout_upd < 0 || our_timeout < *timeout_upd)
> +            *timeout_upd = our_timeout;
> +    }
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +    return rc;
> +}
> +
> +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd 
> *fds,
> +                             struct timeval now) {
> +    int i;
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +
> +    assert(nfds <= CTX->fd_beforepolled_used);
> +
> +    for (i = 0; i < nfds; i++) {
> +        if (!fds[i].revents)
> +            continue;
> +
> +        libxl__ev_fd *efd = CTX->fd_beforepolled[i];
> +        if (!efd)
> +            continue;
> +
> +        assert(efd->in_beforepolled == i);
> +        assert(fds[i].fd == efd->fd);
> +
> +        int revents = fds[i].revents & efd->events;
> +        if (!revents)
> +            continue;
> +
> +        efd->func(gc, efd, efd->fd, efd->events, revents);
> +    }
> +
> +    for (;;) {
> +        libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
> +        if (!etime)
> +            break;
> +
> +        assert(!etime->infinite);
> +
> +        if (timercmp(&etime->abs, &now, >))
> +            break;
> +
> +        time_deregister(gc, etime);
> +
> +        etime->func(gc, etime, &etime->abs);
> +    }
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +
> +/*
> + * osevent hook and callback machinery
> + */
> +
> +void libxl_osevent_register_hooks(libxl_ctx *ctx,
> +                                  const libxl_osevent_hooks *hooks,
> +                                  void *user) {
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +    ctx->osevent_hooks = hooks;
> +    ctx->osevent_user = user;
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +
> +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl,
> +                               int fd, short events, short revents) {
> +    libxl__ev_fd *ev = for_libxl;
> +
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +    assert(!CTX->osevent_in_hook);
> +
> +    assert(fd == ev->fd);
> +    revents &= ev->events;
> +    if (revents)
> +        ev->func(gc, ev, fd, ev->events, revents);
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl) {
> +    libxl__ev_time *ev = for_libxl;
> +
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +    assert(!CTX->osevent_in_hook);
> +
> +    assert(!ev->infinite);
> +    LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
> +    ev->func(gc, ev, &ev->abs);
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval,
> +                           libxl_event_type type /* may be 0 */,
> +                           const char *file, int line, const char *func) {
> +    libxl__log(CTX, XTL_CRITICAL, errnoval, file, line, func,
> +               "DISASTER in event loop: %s%s%s%s",
> +               msg,
> +               type ? " (relates to event type " : "",
> +               type ? libxl_event_type_to_string(type) : "",
> +               type ? ")" : "");
> +
> +    /*
> +     * FIXME: This should call the "disaster" hook supplied to
> +     * libxl_event_register_callbacks, which will be introduced in the
> +     * next patch.
> +     */
> +
> +    const char verybad[] =
> +        "DISASTER in event loop not handled by libxl application";
> +    LIBXL__LOG(CTX, XTL_CRITICAL, verybad);
> +    fprintf(stderr, "libxl: fatal error, exiting program: %s\n", verybad);
> +    exit(-1);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h
> new file mode 100644
> index 0000000..25efbdf
> --- /dev/null
> +++ b/tools/libxl/libxl_event.h
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright (C) 2011      Citrix Ltd.
> + * Author Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#ifndef LIBXL_EVENT_H
> +#define LIBXL_EVENT_H
> +
> +#include <libxl.h>
> +
> +
> +/*======================================================================*/
> +
> +/*
> + * OS event handling - passing low-level OS events to libxl
> + *
> + * Event-driven programs must use these facilities to allow libxl
> + * to become aware of readability/writeability of file descriptors
> + * and the occurrence of timeouts.
> + *
> + * There are two approaches available.  The first is appropriate for
> + * simple programs handling reasonably small numbers of domains:
> + *
> + *   for (;;) {
> + *      libxl_osevent_beforepoll(...)
> + *      poll();
> + *      libxl_osevent_afterpoll(...);
> + *      for (;;) {
> + *        r=libxl_event_check(...);
> + *        if (r==LIBXL_NOT_READY) break;
> + *        if (r) handle failure;
> + *        do something with the event;
> + *      }
> + *   }
> + *
> + * The second approach uses libxl_osevent_register_hooks and is
> + * suitable for programs which are already using a callback-based
> + * event library.
> + *
> + * An application may freely mix the two styles of interaction.
> + */
> +
> +struct pollfd;
> +
> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
> +                             struct pollfd *fds, int *timeout_upd,
> +                             struct timeval now);
> +  /* The caller should provide beforepoll with some space for libxl's
> +   * fds, and tell libxl how much space is available by setting *nfds_io.
> +   * fds points to the start of this space (and fds may be a pointer into
> +   * a larger array, for example, if the application has some fds of
> +   * its own that it is interested in).
> +   *
> +   * On return *nfds_io will in any case have been updated by libxl
> +   * according to how many fds libxl wants to poll on.
> +   *
> +   * If the space was sufficient, libxl fills in fds[0..<new
> +   * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed,
> +   * and returns ok.
> +   *
> +   * If space was insufficient, fds[0..<old *nfds_io>] is undefined on
> +   * return; *nfds_io on return will be greater than the value on
> +   * entry; *timeout_upd may or may not have been updated; and
> +   * libxl_osevent_beforepoll returns ERROR_BUFERFULL.  In this case
> +   * the application needs to make more space (enough space for
> +   * *nfds_io struct pollfd) and then call beforepoll again, before
> +   * entering poll(2).  Typically this will involve calling realloc.
> +   *
> +   * The application may call beforepoll with fds==NULL and
> +   * *nfds_io==0 in order to find out how much space is needed.
> +   *
> +   * *timeout_upd is as for poll(2): it's in milliseconds, and
> +   * negative values mean no timeout (infinity).
> +   * libxl_osevent_beforepoll will only reduce the timeout, naturally.
> +   */

so far we have always added the comment on a function above the
declaration of the function; we should keep doing it for consistency


> +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd 
> *fds,
> +                             struct timeval now);
> +  /* nfds and fds[0..nfds] must be from the most recent call to
> +   * _beforepoll, as modified by poll.
> +   *
> +   * This function actually performs all of the IO and other actions,
> +   * and generates events (libxl_event), which are implied by either
> +   * (a) the time of day or (b) both (i) the returned information from
> +   * _beforepoll, and (ii) the results from poll specified in
> +   * fds[0..nfds-1].  Generated events can then be retrieved by
> +   * libxl_event_check.
> +   */
> +

I see that the implementation of libxl_event_check is actually missing
from this patch.
Is this patch supposed to compiled, even without the actual libxl_event
generation? Or are the two patches have to be committed together?


> +typedef struct libxl_osevent_hooks {
> +  int (*fd_register)(void *uselibxl_event_check.r, int fd, void 
> **for_app_registration_out,
> +                     short events, void *for_libxl);
> +  int (*fd_modify)(void *user, int fd, void **for_app_registration_update,
> +                   short events);
> +  void (*fd_deregister)(void *user, int fd, void *for_app_registration);
> +  int (*timeout_register)(void *user, void **for_app_registration_out,
> +                          struct timeval abs, void *for_libxl);
> +  int (*timeout_modify)(void *user, void **for_app_registration_update,
> +                         struct timeval abs);
> +  void (*timeout_deregister)(void *user, void *for_app_registration_io);
> +} libxl_osevent_hooks;
> +
> +void libxl_osevent_register_hooks(libxl_ctx *ctx,
> +                                  const libxl_osevent_hooks *hooks,
> +                                  void *user);
> +  /* The application which calls register_fd_hooks promises to
> +   * maintain a register of fds and timeouts that libxl is interested
> +   * in, and make calls into libxl (libxl_osevent_occurred_*)
> +   * when those fd events and timeouts occur.  This is more efficient
> +   * than _beforepoll/_afterpoll if there are many fds (which can
> +   * happen if the same libxl application is managing many domains).
> +   *
> +   * For an fd event, events is as for poll().  register or modify may
> +   * be called with events==0, in which case it must still work
> +   * normally, just not generate any events.
> +   *
> +   * For a timeout event, milliseconds is as for poll().
> +   * Specifically, negative values of milliseconds mean NO TIMEOUT.
> +   * This is used by libxl to temporarily disable a timeout.
> +   *
> +   * If the register or modify hook succeeds it may update
> +   * *for_app_registration_out/_update and must then return 0.
> +   * On entry to register, *for_app_registration_out is always NULL.
> +   *
> +   * A registration or modification hook may fail, in which case it
> +   * must leave the registration state of the fd or timeout unchanged.
> +   * It may then either return ERROR_OSEVENT_REG_FAIL or any positive
> +   * int.  The value returned will be passed up through libxl and
> +   * eventually returned back to the application.  When register
> +   * fails, any value stored into *for_registration_out is ignored by
> +   * libxl; when modify fails, any changed value stored into
> +   * *for_registration_update is honoured by libxl and will be passed
> +   * to future modify or deregister calls.
> +   *
> +   * libxl will only attempt to register one callback for any one fd.
> +   * libxl will remember the value stored in *for_app_registration_io
> +   * by a successful call to register or modify and pass it into
> +   * subsequent calls to modify or deregister.
> +   *
> +   * register_fd_hooks may be called only once for each libxl_ctx.
> +   * libxl may make calls to register/modify/deregister from within
> +   * any libxl function (indeed, it will usually call register from
> +   * register_event_hooks).  Conversely, the application MUST NOT make
> +   * the event occurrence calls (libxl_osevent_occurred_*) into libxl
> +   * reentrantly from within libxl (for example, from within the
> +   * register/modify functions).
> +   *
> +   * Lock hierarchy: the register/modify/deregister functions may be
> +   * called with locks held.  These locks (the "libxl internal locks")
> +   * are inside the libxl_ctx.  Therefore, if those register functions
> +   * acquire any locks of their own ("caller register locks") outside
> +   * libxl, to avoid deadlock one of the following must hold for each
> +   * such caller register lock:
> +   *  (a) "acquire libxl internal locks before caller register lock":
> +   *      No libxl function may be called with the caller register
> +   *      lock held.
> +   *  (b) "acquire caller register lock before libxl internal locks":
> +   *      No libxl function may be called _without_ the caller
> +   *      register lock held.
> +   * Of these we would normally recommend (a).
> +   *
> +   * The value *hooks is not copied and must outlast the libxl_ctx.
> +   */

while this description is very verbose, it doesn't contain informations
on:

- what is void *user;
- what is "const libxl_osevent_hooks *hooks", in particular the role of
  each  of these function pointers and the description of their
  arguments.

If I am a user of the library, how am I supposed to pass as user? and as
hooks?
I think these few lines should go first, then the description of the
contract.


> +/* It is NOT legal to call _occurred_ reentrantly within any libxl
> + * function.  Specifically it is NOT legal to call it from within
> + * a register callback.  Conversely, libxl MAY call register/deregister
> + * from within libxl_event_registered_call_*.
> + */
> +
> +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl,
> +                               int fd, short events, short revents);
> +
> +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl);
> +  /* Implicitly, on entry to this function the timeout has been
> +   * deregistered.  If _occurred_timeout is called, libxl will not
> +   * call timeout_deregister; if it wants to requeue the timeout it
> +   * will call timeout_register again.
> +   */
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index d015c7c..88e7dbb 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -24,6 +24,9 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <pthread.h>
> +#include <inttypes.h>
> +#include <assert.h>
> +#include <sys/poll.h>
> 
>  #include <xs.h>
>  #include <xenctrl.h>
> @@ -91,6 +94,66 @@ _hidden void libxl__log(libxl_ctx *ctx, xentoollog_level 
> msglevel, int errnoval,
> 
>       /* these functions preserve errno (saving and restoring) */
> 
> +typedef struct libxl__gc libxl__gc;
> +
> +typedef struct libxl__ev_fd libxl__ev_fd;
> +typedef void libxl__ev_fd_callback(libxl__gc *gc, libxl__ev_fd *ev,
> +                                   int fd, short events, short revents);
> +struct libxl__ev_fd {
> +    /* all private for libxl__ev_fd... */
> +    LIBXL_LIST_ENTRY(libxl__ev_fd) entry;
> +    int fd;
> +    short events;
> +    int in_beforepolled; /* -1 means not in fd_beforepolled */
> +    void *for_app_reg;
> +    libxl__ev_fd_callback *func;
> +};
> +
> +
> +typedef struct libxl__ev_time libxl__ev_time;
> +typedef void libxl__ev_time_callback(libxl__gc *gc, libxl__ev_time *ev,
> +                                     const struct timeval *requested_abs);
> +struct libxl__ev_time {
> +    /* all private for libxl__ev_time... */
> +    int infinite; /* not registered in list or with app if infinite */
> +    LIBXL_TAILQ_ENTRY(libxl__ev_time) entry;
> +    struct timeval abs;
> +    void *for_app_reg;
> +    libxl__ev_time_callback *func;
> +};
> +
> +typedef struct libxl__ev_xswatch libxl__ev_xswatch;
> +typedef void libxl__ev_xswatch_callback(libxl__gc *gc, libxl__ev_xswatch*,
> +                            const char *watch_path, const char *event_path);
> +struct libxl__ev_xswatch {
> +    /* caller should include this in their own struct */
> +    /* contents are private to xswatch_register */
> +    int slotnum;
> +    uint32_t counterval;
> +    char *path;
> +    libxl__ev_xswatch_callback *callback;
> +};
> +
> +/*
> + * An entry in the watch_slots table is either:
> + *  1. an entry in the free list, ie NULL or pointer to next free list entry
> + *  2. an pointer to a libxl__ev_xswatch
> + *
> + * But we don't want to use unions or type-punning because the
> + * compiler might "prove" that our code is wrong and misoptimise it.
> + *
> + * The rules say that all struct pointers have identical
> + * representation and alignment requirements (C99+TC1+TC2 6.2.5p26) so
> + * what we do is simply declare our array as containing only the free
> + * list pointers, and explicitly convert from and to our actual
> + * xswatch pointers when we store and retrieve them.
> + */
> +typedef struct libxl__ev_watch_slot {
> +    LIBXL_SLIST_ENTRY(struct libxl__ev_watch_slot) empty;
> +} libxl__ev_watch_slot;
> +
> +libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum);
> +
>  struct libxl__ctx {
>      xentoollog_logger *lg;
>      xc_interface *xch;
> @@ -108,6 +171,23 @@ struct libxl__ctx {
>         * documented in the libxl public interface.
>         */
> 
> +    int osevent_in_hook;
> +    const libxl_osevent_hooks *osevent_hooks;
> +    void *osevent_user;
> +      /* See the comment for OSEVENT_HOOK_INTERN in libxl_event.c
> +       * for restrictions on the use of the osevent fields. */
> +
> +    int fd_beforepolled_allocd, fd_beforepolled_used;
> +    libxl__ev_fd **fd_beforepolled; /* see libxl_osevent_beforepoll */
> +    LIBXL_LIST_HEAD(, libxl__ev_fd) efds;
> +    LIBXL_TAILQ_HEAD(, libxl__ev_time) etimes;
> +
> +    libxl__ev_watch_slot *watch_slots;
> +    int watch_nslots;
> +    LIBXL_SLIST_HEAD(, libxl__ev_watch_slot) watch_freeslots;
> +    uint32_t watch_counter; /* helps disambiguate slot reuse */
> +    libxl__ev_fd watch_efd;
> +
>      /* for callers who reap children willy-nilly; caller must only
>       * set this after libxl_init and before any other call - or
>       * may leave them untouched */
> @@ -138,12 +218,12 @@ typedef struct {
> 
>  #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y)))
> 
> -typedef struct {
> +struct libxl__gc {
>      /* mini-GC */
>      int alloc_maxsize;
>      void **alloc_ptrs;
>      libxl_ctx *owner;
> -} libxl__gc;
> +};
> 
>  #define LIBXL_INIT_GC(gc,ctx) do{               \
>          (gc).alloc_maxsize = 0;                 \
> @@ -209,9 +289,137 @@ _hidden char *libxl__xs_read(libxl__gc *gc, 
> xs_transaction_t t,
>  _hidden char **libxl__xs_directory(libxl__gc *gc, xs_transaction_t t,
>                                     const char *path, unsigned int *nb);
>     /* On error: returns NULL, sets errno (no logging) */
> -
>  _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid);
> 
> +
> +/*
> + * Event generation functions provided by the libxl event core to the
> + * rest of libxl.  Implemented in terms of _beforepoll/_afterpoll
> + * and/or the fd registration machinery, as provided by the
> + * application.
> + *
> + * Semantics are similar to those of the fd and timeout registration
> + * functions provided to libxl_osevent_register_hooks.
> + *
> + * Non-0 returns from libxl__ev_{modify,deregister} have already been
> + * logged by the core and should be returned unmodified to libxl's
> + * caller; NB that they may be valid libxl error codes but they may
> + * also be positive numbers supplied by the caller.
> + *
> + * In each case, there is a libxl__ev_FOO structure which can be in
> + * one of three states:
> + *
> + *   Undefined   - Might contain anything.  All-bits-zero is
> + *                 an undefined state.
> + *
> + *   Idle        - Struct contents are defined enough to pass to any
> + *                 libxl__ev_FOO function but not registered and
> + *                 callback will not be called.  The struct does not
> + *                 contain references to any allocated resources so
> + *                 can be thrown away.
> + *
> + *   Active      - Request for events has been registered and events
> + *                 may be generated.  _deregister must be called to
> + *                 reclaim resources.
> + *
> + * These functions are provided for each kind of event KIND:
> + *
> + *   int libxl__ev_KIND_register(libxl__gc *gc, libxl__ev_KIND *GEN,
> + *                              libxl__ev_KIND_callback *FUNC,
> + *                              DETAILS);
> + *      On entry *GEN must be in state Undefined or Idle.
> + *      Returns a libxl error code; on error return *GEN is Idle.
> + *      On successful return *GEN is Active and FUNC wil be
> + *      called by the event machinery in future.  FUNC will
> + *      not be called from within the call to _register.
> + *
> + *  void libxl__ev_KIND_deregister(libxl__gc *gc, libxl__ev_KIND *GEN_upd);
> + *      On entry *GEN must be in state Active or Idle.
> + *      On return it is Idle.  (Idempotent.)
> + *
> + *  void libxl__ev_KIND_init(libxl__ev_KIND *GEN);
> + *      Provided for initialising an Undefined KIND.
> + *      On entry *GEN must be in state Idle or Undefined.
> + *      On return it is Idle.  (Idempotent.)
> + *
> + *  int libxl__ev_KIND_isregistered(const libxl__ev_KIND *GEN);
> + *      On entry *GEN must be Idle or Active.
> + *      Returns nonzero if it is Active, zero otherwise.
> + *      Cannot fail.
> + *
> + *  int libxl__ev_KiND_modify(libxl__gc*, libxl__ev_KIND *GEN,
> + *                            DETAILS);
> + *      Only provided for some kinds of generator.
> + *      On entry *GEN must be Active and on return, whether successful
> + *      or not, it will be Active.
> + *      Returns a libxl error code; on error the modification
> + *      is not effective.
> + *
> + * All of these functions are fully threadsafe and may be called by
> + * general code in libxl even from within event callback FUNCs.
> + */
> +
> +
> +_hidden int libxl__ev_fd_register(libxl__gc*, libxl__ev_fd *ev_out,
> +                                  libxl__ev_fd_callback*,
> +                                  int fd, short events /* as for poll(2) */);
> +_hidden int libxl__ev_fd_modify(libxl__gc*, libxl__ev_fd *ev,
> +                                short events);
> +_hidden void libxl__ev_fd_deregister(libxl__gc*, libxl__ev_fd *ev);
> +static inline void libxl__ev_fd_init(libxl__ev_fd *efd)
> +                    { efd->fd = -1; }
> +static inline int libxl__ev_fd_isregistered(libxl__ev_fd *efd)
> +                    { return efd->fd >= 0; }
> +
> +_hidden int libxl__ev_time_register_rel(libxl__gc*, libxl__ev_time *ev_out,
> +                                        libxl__ev_time_callback*,
> +                                        int milliseconds /* as for poll(2) 
> */);
> +_hidden int libxl__ev_time_register_abs(libxl__gc*, libxl__ev_time *ev_out,
> +                                        libxl__ev_time_callback*,
> +                                        struct timeval);
> +_hidden int libxl__ev_time_modify_rel(libxl__gc*, libxl__ev_time *ev,
> +                                      int milliseconds /* as for poll(2) */);
> +_hidden int libxl__ev_time_modify_abs(libxl__gc*, libxl__ev_time *ev,
> +                                      struct timeval);
> +_hidden void libxl__ev_time_deregister(libxl__gc*, libxl__ev_time *ev);
> +static inline void libxl__ev_time_init(libxl__ev_time *ev)
> +                { ev->func = 0; }
> +static inline int libxl__ev_time_isregistered(libxl__ev_time *ev)
> +                { return !!ev->func; }
> +
> +
> +_hidden int libxl__ev_xswatch_register(libxl__gc*, libxl__ev_xswatch 
> *xsw_out,
> +                                       libxl__ev_xswatch_callback*,
> +                                       const char *path /* copied */);
> +_hidden void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch*);
> +
> +static inline void libxl__ev_xswatch_init(libxl__ev_xswatch *xswatch_out)
> +                { xswatch_out->slotnum = -1; }
> +static inline int libxl__ev_xswatch_isregistered(const libxl__ev_xswatch *xw)
> +                { return xw->slotnum >= 0; }
> +
> +
> +
> +_hidden void libxl__event_disaster(libxl__gc*, const char *msg, int errnoval,
> +                                   libxl_event_type type /* may be 0 */,
> +                                   const char *file, int line,
> +                                   const char *func);
> +  /*
> +   * In general, call this via the macro LIBXL__EVENT_DISASTER.
> +   *
> +   * Event-generating functions may call this if they might have
> +   * wanted to generate an event (either an internal one ie a
> +   * libxl__ev_FOO_callback or an application event), but are
> +   * prevented from doing so due to eg lack of memory.
> +   *
> +   * NB that this function may return and the caller isn't supposed to
> +   * then crash, although it may fail (and henceforth leave things in
> +   * a state where many or all calls fail).
> +   */
> +#define LIBXL__EVENT_DISASTER(gc, msg, errnoval, type) \
> +    libxl__event_disaster(gc, msg, errnoval, type, __FILE__, __LINE__, 
> __func__)

any reason why this shouldn't be a static inline?

> +
>  /* from xl_dom */
>  _hidden libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid);
>  _hidden int libxl__domain_shutdown_reason(libxl__gc *gc, uint32_t domid);
> @@ -536,6 +744,8 @@ _hidden int libxl__parse_mac(const char *s, libxl_mac 
> mac);
>  /* compare mac address @a and @b. 0 if the same, -ve if a<b and +ve if a>b */
>  _hidden int libxl__compare_macs(libxl_mac *a, libxl_mac *b);
> 
> +_hidden int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r);
> +
>  #define STRINGIFY(x) #x
>  #define TOSTRING(x) STRINGIFY(x)
> 
> --
> 1.7.2.5
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel
> 

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.