[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



> [...snip already reviewed bits...]
> +/*
> + * osevent poll
> + */
> +
> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
> +                             struct pollfd *fds, int *timeout_upd,
> +                             struct timeval now) {
> +    libxl__ev_fd *efd;
> +    int i;
> +
> +    /*
> +     * In order to be able to efficiently find the libxl__ev_fd
> +     * for a struct poll during _afterpoll, we maintain a shadow
> +     * data structure in CTX->fd_beforepolled: each slot in
> +     * the fds array corresponds to a slot in fd_beforepolled.
> +     */
> +
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +
> +    if (*nfds_io) {
> +        /*
> +         * As an optimisation, we don't touch fd_beforepolled_used
> +         * if *nfds_io is zero on entry, since in that case the
> +         * caller just wanted to know how big an array to give us.
> +         *
> +         * If !*nfds_io, the unconditional parts below are guaranteed
> +         * not to mess with fd_beforepolled... or any in_beforepolled.
> +         */
> +
> +        /* Remove all the old references into beforepolled */
> +        for (i = 0; i < CTX->fd_beforepolled_used; i++) {
> +            efd = CTX->fd_beforepolled[i];
> +            if (efd) {
> +                assert(efd->in_beforepolled == i);
> +                efd->in_beforepolled = -1;
> +                CTX->fd_beforepolled[i] = NULL;
> +            }
> +        }
> +        CTX->fd_beforepolled_used = 0;
> +
> +        /* make sure our array is as big as *nfds_io */
> +        if (CTX->fd_beforepolled_allocd < *nfds_io) {
> +            assert(*nfds_io < INT_MAX / sizeof(libxl__ev_fd*) / 2);

What is the /2 for?

> +            libxl__ev_fd **newarray =
> +                realloc(CTX->fd_beforepolled, sizeof(*newarray) * *nfds_io);
> +            if (!newarray)
> +                return ERROR_NOMEM;

Need to CTX_UNLOCK here.

> +            CTX->fd_beforepolled = newarray;
> +            CTX->fd_beforepolled_allocd = *nfds_io;
> +        }
> +    }
> +
> +    int used = 0;
> +    LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) {
> +        if (used < *nfds_io) {
> +            fds[used].fd = efd->fd;
> +            fds[used].events = efd->events;
> +            fds[used].revents = 0;
> +            CTX->fd_beforepolled[used] = efd;
> +            efd->in_beforepolled = used;
> +        }
> +        used++;
> +    }
> +    int rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL;
> +
> +    if (*nfds_io) {
> +        CTX->fd_beforepolled_used = used;
> +    }
> +
> +    *nfds_io = used;
> +
> +    libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
> +    if (etime) {
> +        int our_timeout;
> +        struct timeval rel;
> +        static struct timeval zero;
> +
> +        timersub(&etime->abs, &now, &rel);
> +
> +        if (timercmp(&rel, &zero, <)) {
> +            our_timeout = 0;
> +        } else if (rel.tv_sec >= 2000000) {
> +            our_timeout = 2000000000;
> +        } else {
> +            our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000;
> +        }
> +        if (*timeout_upd < 0 || our_timeout < *timeout_upd)
> +            *timeout_upd = our_timeout;
> +    }
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +    return rc;
> +}
> +
> +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd 
> *fds,
> +                             struct timeval now) {
> +    int i;
> +    GC_INIT(ctx);
> +    CTX_LOCK;
> +
> +    assert(nfds <= CTX->fd_beforepolled_used);
> +
> +    for (i = 0; i < nfds; i++) {
> +        if (!fds[i].revents)
> +            continue;
> +
> +        libxl__ev_fd *efd = CTX->fd_beforepolled[i];
> +        if (!efd)
> +            continue;

Would this be a bug? If we've set it up for polling how can it be NULL?

> +
> +        assert(efd->in_beforepolled == i);
> +        assert(fds[i].fd == efd->fd);
> +
> +        int revents = fds[i].revents & efd->events;
> +        if (!revents)
> +            continue;
> +
> +        efd->func(gc, efd, efd->fd, efd->events, revents);
> +    }
> +
> +    for (;;) {
> +        libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
> +        if (!etime)
> +            break;
> +
> +        assert(!etime->infinite);
> +
> +        if (timercmp(&etime->abs, &now, >))
> +            break;
> +
> +        time_deregister(gc, etime);
> +
> +        etime->func(gc, etime, &etime->abs);
> +    }
> +
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +
> +/*
> + * osevent hook and callback machinery
> + */
> +
> +void libxl_osevent_register_hooks(libxl_ctx *ctx,
> +                                  const libxl_osevent_hooks *hooks,
> +                                  void *user) {
> +    GC_INIT(ctx);

I nearly said, "there's no gc used in this function" but actually it is
artfully concealed in CTX_LOCK.

I wonder if CTX_LOCK should take the context, e.g. either CTX_LOCK(CTX)
or CTX_LOCK(ctx)?

Another alternative would be to have CTX_INIT to parallel GC_INIT which
creates a local *ctx instead of having CTX. This would also avoid the
need to s/CTX/ctx/ if you make an internal function into an external one
and vice versa.

> +    CTX_LOCK;
> +    ctx->osevent_hooks = hooks;
> +    ctx->osevent_user = user;
> +    CTX_UNLOCK;
> +    GC_FREE;
> +}
> +
> +
[...]
> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h
> new file mode 100644
> index 0000000..25efbdf
> --- /dev/null
> +++ b/tools/libxl/libxl_event.h
> @@ -0,0 +1,199 @@
[...]
> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
> +                             struct pollfd *fds, int *timeout_upd,
> +                             struct timeval now);
> +  /* The caller should provide beforepoll with some space for libxl's
> +   * fds, and tell libxl how much space is available by setting *nfds_io.
> +   * fds points to the start of this space (and fds may be a pointer into
> +   * a larger array, for example, if the application has some fds of
> +   * its own that it is interested in).
> +   *
> +   * On return *nfds_io will in any case have been updated by libxl
> +   * according to how many fds libxl wants to poll on.
> +   *
> +   * If the space was sufficient, libxl fills in fds[0..<new
> +   * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed,
> +   * and returns ok.
> +   *
> +   * If space was insufficient, fds[0..<old *nfds_io>] is undefined on
> +   * return; *nfds_io on return will be greater than the value on
> +   * entry; *timeout_upd may or may not have been updated; and
> +   * libxl_osevent_beforepoll returns ERROR_BUFERFULL.  In this case

                                         ERROR_BUFFERFULL
[...]

> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index d015c7c..88e7dbb 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
[...]
> @@ -138,12 +218,12 @@ typedef struct {
> 
>  #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y)))
> 
> -typedef struct {
> +struct libxl__gc {
>      /* mini-GC */
>      int alloc_maxsize;
>      void **alloc_ptrs;
>      libxl_ctx *owner;
> -} libxl__gc;
> +};

Is this an unrelated change which has snuck in? I'd hack expected an
equivalent change to GC_INIT if not.

[...]
> --
> 1.7.2.5

Phew!



_______________________________________________
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®.