|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |