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

Re: [Xen-devel] [PATCH RFC v2 13/13] libxl: New event generation API



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

On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> Replace the existing API for retrieving high-level events (events
> about domains, etc.) from libxl with a new one.
> 
> This changes the definition and semantics of the `libxl_event'
> structure, and replaces the calls for obtaining information about
> domain death and disk eject events.
> 
> This is an incompatible change, sorry.  The alternative was to try to
> provide both the previous horrid API and the new one, and would also
> involve never using the name `libxl_event' for the new interface.
> 
> Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> ---
>  tools/libxl/libxl.c          |  306 +++++++++++++++++++++++++++++------------
>  tools/libxl/libxl.h          |   55 ++-------
>  tools/libxl/libxl_event.c    |  182 +++++++++++++++++++++++---
>  tools/libxl/libxl_event.h    |  172 +++++++++++++++++++++++
>  tools/libxl/libxl_internal.c |    6 +
>  tools/libxl/libxl_internal.h |   66 +++++++++
>  tools/libxl/libxl_types.idl  |   35 ++++-
>  tools/libxl/xl_cmdimpl.c     |  261 +++++++++++++++++++++---------------
>  8 files changed, 815 insertions(+), 268 deletions(-)
> 
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index da06ed2..4759c18 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -53,7 +53,10 @@
>   *    A public function may be called from within libxl; the call
>   *    context initialisation macros will make sure that the internal
>   *    caller's context is reused (eg, so that the same xenstore
> - *    transaction is used).
> + *    transaction is used).  But in-libxl callers of libxl public
> + *    functions should note that any libxl public function may cause
> + *    recursively reentry into libxl via the application's event
> + *    callback hook.
>   *
>   *    Public functions have names like libxl_foobar.
>   *
> @@ -152,6 +155,8 @@ void libxl_key_value_list_destroy(libxl_key_value_list 
> *kvl);
> 
>  typedef uint32_t libxl_hwcap[8];
> 
> +typedef uint64_t libxl_ev_user;
> +
>  typedef struct {
>      uint32_t size;          /* number of bytes in map */
>      uint8_t *map;
> @@ -200,6 +205,9 @@ typedef struct {
>      int v;
>  } libxl_enum_string_table;
> 
> +struct libxl_event;
> +typedef LIBXL_TAILQ_ENTRY(struct libxl_event) libxl_ev_link;
> +
>  typedef struct libxl__ctx libxl_ctx;
> 
>  #include "_libxl_types.h"
> @@ -295,51 +303,6 @@ int libxl_run_bootloader(libxl_ctx *ctx,
> 
>    /* 0 means ERROR_ENOMEM, which we have logged */
> 
> -/* events handling */
> -
> -typedef struct {
> -    /* event type */
> -    libxl_event_type type;
> -    /* data for internal use of the library */
> -    char *path;
> -    char *token;
> -} libxl_event;
> -
> -typedef struct {
> -    char *path;
> -    char *token;
> -} libxl_waiter;
> -
> -
> -int libxl_get_wait_fd(libxl_ctx *ctx, int *fd);
> -/* waiter is allocated by the caller */
> -int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter 
> *waiter);
> -/* waiter is a preallocated array of num_disks libxl_waiter elements */
> -int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t domid, 
> libxl_device_disk *disks, int num_disks, libxl_waiter *waiter);
> -int libxl_get_event(libxl_ctx *ctx, libxl_event *event);
> -int libxl_stop_waiting(libxl_ctx *ctx, libxl_waiter *waiter);
> -int libxl_free_event(libxl_event *event);
> -int libxl_free_waiter(libxl_waiter *waiter);
> -
> -/*
> - * Returns:
> - *  - 0 if the domain is dead but there is no cleanup to be done. e.g
> - *    because someone else has already done it.
> - *  - 1 if the domain is dead and there is cleanup to be done.
> - *
> - * Can return error if the domain exists and is still running.
> - *
> - * *info will contain valid domain state iff 1 is returned. In
> - * particular if 1 is returned then info->shutdown_reason is
> - * guaranteed to be valid since by definition the domain is
> - * (shutdown||dying))
> - */
> -int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, 
> libxl_event *event, libxl_dominfo *info);
> -
> -/*
> - * Returns true and fills *disk if the caller should eject the disk
> - */
> -int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, 
> libxl_event *event, libxl_device_disk *disk);
> 
>  int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
>                          const char *old_name, const char *new_name);
[...]
> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h
> index 48c6277..c52addc 100644
> --- a/tools/libxl/libxl_event.h
> +++ b/tools/libxl/libxl_event.h
> @@ -18,6 +18,178 @@
> 
>  #include <libxl.h>
> 
> +/*======================================================================*/
> +
> +/*
> + * Domain event handling - getting Xen events from libxl
> + */
> +
> +#define LIBXL_EVENTMASK_ALL (~(unsigned long)0)
> +
> +typedef int libxl_event_predicate(const libxl_event*, void *user);
> +  /* Return value is 0 if the event is unwanted or non-0 if it is.
> +   * Predicates are not allowed to fail.
> +   */
> +
> +int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r,
> +                      unsigned long typemask,
> +                      libxl_event_predicate *predicate, void 
> *predicate_user);
> +  /* Searches for an event, already-happened, which matches typemask
> +   * and predicate.  predicate==0 matches any event.
> +   * libxl_event_check returns the event, which must then later be
> +   * freed by the caller using libxl_event_free.
> +   *
> +   * Returns ERROR_NOT_READY if no such event has happened.
> +   */
> +
> +int libxl_event_wait(libxl_ctx *ctx, libxl_event **event_r,
> +                     unsigned long typemask,
> +                     libxl_event_predicate *predicate, void *predicate_user);
> +  /* Like libxl_event_check but blocks if no suitable events are
> +   * available, until some are.  Uses libxl_osevent_beforepoll/
> +   * _afterpoll so may be inefficient if very many domains are being
> +   * handled by a single program.
> +   */
> +
> +int libxl_event_free(libxl_ctx *ctx, libxl_event *event);
> +
> +
> +/* Alternatively or additionally, the application may also use this: */
> +
> +typedef struct libxl_event_hooks {
> +    uint64_t event_occurs_mask;
> +    void (*event_occurs)(void *user, const libxl_event *event);
> +    void (*disaster)(void *user, libxl_event_type type,
> +                     const char *msg, int errnoval);
> +} libxl_event_hooks;
> +
> +void libxl_event_register_callbacks(libxl_ctx *ctx,
> +                                    const libxl_event_hooks *hooks, void 
> *user);
> +  /*
> +   * Arranges that libxl will henceforth call event_occurs for any
> +   * events whose type is set in event_occurs_mask, rather than
> +   * queueing the event for retrieval by libxl_event_check/wait.
> +   * Events whose bit is clear in mask are not affected.
> +   *
> +   * event becomes owned by the application and must be freed, either
> +   * by event_occurs or later.
> +   *
> +   * event_occurs may be NULL if mask is 0.
> +   *
> +   * libxl_event_register_callback also provides a way for libxl to
> +   * report to the application that there was a problem reporting
> +   * events; this can occur due to lack of host memory during event
> +   * handling, or other wholly unrecoverable errors from system calls
> +   * made by libxl.  This will not happen for frivolous reasons - only
> +   * if the system, or the Xen components of it, are badly broken.
> +   *
> +   * msg and errnoval will describe the action that libxl was trying
> +   * to do, and type specifies the type of libxl events which may be
> +   * missing.  type may be 0 in which case events of all types may be
> +   * missing.
> +   *
> +   * disaster may be NULL.  If it is, or if _register_callbacks has
> +   * not been called, errors of this kind are fatal to the entire
> +   * application: libxl will print messages to its logs and to stderr
> +   * and call exit(-1).
> +   *
> +   * If disaster returns, it may be the case that some or all future
> +   * libxl calls will return errors; likewise it may be the case that
> +   * no more events (of the specified type, if applicable) can be
> +   * produced.  An application which supplies a disaster function
> +   * should normally react either by exiting, or by (when it has
> +   * returned to its main event loop) shutting down libxl with
> +   * libxl_ctx_free and perhaps trying to restart it with
> +   * libxl_ctx_init.
> +   *
> +   * In any case before calling disaster, libxl will have logged a
> +   * message with level XTL_CRITICAL.
> +   *
> +   * Reentrancy: it IS permitted to call libxl from within
> +   * event_occurs.  It is NOT permitted to call libxl from within
> +   * disaster.
> +   *
> +   * libxl_event_register_callbacks may be called as many times, with
> +   * different parameters, as the application likes; the most recent
> +   * call determines the libxl behaviour.  However it is NOT safe to
> +   * call _register_callbacks concurrently with, or reentrantly from,
> +   * any other libxl function.
> +   *
> +   * Calls to _register_callbacks do not affect events which have
> +   * already occurred.
> +   */
> +
> +
> +/*
> + * Events are only generated if they have been requested.
> + * The following functions request the generation of specific events.
> + *
> + * Each set of functions for controlling event generation has this form:
> + *
> + *   typedef struct libxl__evgen_FOO libxl__evgen_FOO;
> + *   int libxl_evenable_FOO(libxl_ctx *ctx, FURTHER PARAMETERS,
> + *                          libxl_ev_user user, libxl__evgen_FOO 
> **evgen_out);
> + *   void libxl_evdisable_FOO(libxl_ctx *ctx, libxl__evgen_FOO *evgen);
> + *
> + * The evenable function arranges that the events (as described in the
> + * doc comment for the individual function) will start to be generated
> + * by libxl.  On success, *evgen_out is set to a non-null pointer to
> + * an opaque struct.
> + *
> + * The user value is returned in the generated events and may be
> + * used by the caller for whatever it likes.  The type ev_user is
> + * guaranteed to be an unsigned integer type which is at least
> + * as big as uint64_t and is also guaranteed to be big enough to
> + * contain any intptr_t value.
> + *
> + * If it becomes desirable to stop generation of the relevant events,
> + * or to reclaim the resources in libxl associated with the evgen
> + * structure, the same evgen value should be passed to the evdisable
> + * function.  However, note that events which occurred prior to the
> + * evdisable call may still be returned.
> + *
> + * The caller may enable identical events more than once.  If they do
> + * so, each actual occurrence will generate several events to be
> + * returned by libxl_event_check, with the appropriate user value(s).
> + * Aside from this, each occurrence of each event is returned by
> + * libxl_event_check exactly once.
> + *
> + * An evgen is associated with the libxl_ctx used for its creation.
> + * After libxl_ctx_free, all corresponding evgen handles become
> + * invalid and must no longer be passed to evdisable.
> + *
> + * Events enabled with evenable prior to a fork and libxl_ctx_postfork
> + * are no longer generated after the fork/postfork; however the evgen
> + * structures are still valid and must be passed to evdisable if the
> + * memory they use should not be leaked.
> + *
> + * Applications should ensure that they eventually retrieve every
> + * event using libxl_event_check or libxl_event_wait, since events
> + * which occur but are not retreived by the application will be queued
> + * inside libxl indefinitely.  libxl_event_check/_wait may be O(n)
> + * where n is the number of queued events which do not match the
> + * criteria specified in the arguments to check/wait.
> + */
> +
> +typedef struct libxl__evgen_domain_death libxl_evgen_domain_death;
> +int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_ev_user, libxl_evgen_domain_death 
> **evgen_out);
> +void libxl_evdisable_domain_death(libxl_ctx *ctx, libxl_evgen_domain_death*);
> +  /* Arranges for the generation of DOMAIN_SHUTDOWN and DOMAIN_DESTROY
> +   * events.  A domain which is destroyed before it shuts down
> +   * may generate only a DESTROY event.
> +   */
> +
> +typedef struct libxl__evgen_disk_eject libxl_evgen_disk_eject;
> +int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t domid, const char 
> *vdev,
> +                        libxl_ev_user, libxl_evgen_disk_eject **evgen_out);
> +void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject*);
> +  /* Arranges for the generation of DISK_EJECT events.  A copy of the
> +   * string *vdev will be made for libxl's internal use, and a pointer
> +   * to this (or some other) copy will be returned as the vdev
> +   * member of event.u.
> +   */
> +
> 
>  /*======================================================================*/
> 
> diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
> index 62e7fba..202ba89 100644
> --- a/tools/libxl/libxl_internal.c
> +++ b/tools/libxl/libxl_internal.c
> @@ -74,6 +74,12 @@ void libxl__free_all(libxl__gc *gc)
>      free(gc->alloc_ptrs);
>      gc->alloc_ptrs = 0;
>      gc->alloc_maxsize = 0;
> +
> +    libxl_event *ev, *ev_tmp;
> +    LIBXL_TAILQ_FOREACH_SAFE(ev, &gc->occurred_for_callback, link, ev_tmp) {
> +        LIBXL_TAILQ_REMOVE(&gc->occurred_for_callback, ev, link);
> +        CTX->event_hooks->event_occurs(CTX->event_hooks_user, ev);
> +    }
>  }
> 
>  void *libxl__zalloc(libxl__gc *gc, int bytes)
[...]
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 93fb8cd..53c07ee 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -75,11 +75,6 @@ libxl_action_on_shutdown = 
> Enumeration("action_on_shutdown", [
>      (6, "COREDUMP_RESTART"),
>      ])
> 
> -libxl_event_type = Enumeration("event_type", [
> -    (1, "DOMAIN_DEATH"),
> -    (2, "DISK_EJECT"),
> -    ])
> -
>  libxl_button = Enumeration("button", [
>      (1, "POWER"),
>      (2, "SLEEP"),
> @@ -374,3 +369,33 @@ libxl_sched_credit = Struct("sched_credit", [
>      ("weight", integer),
>      ("cap", integer),
>      ], destructor_fn=None)
> +
> +libxl_event_type = Enumeration("event_type", [
> +    (1, "DOMAIN_SHUTDOWN"),
> +    (2, "DOMAIN_DESTROY"),
> +    (3, "DISK_EJECT"),
> +    ])
> +
> +libxl_ev_user = Number("libxl_ev_user")
> +
> +libxl_ev_link = Builtin("ev_link", passby=PASS_BY_REFERENCE, c_only=True)
> +
> +libxl_event = Struct("event",[
> +    ("link",     libxl_ev_link,0,
> +     "for use by libxl; caller may use this once the event has been"
> +     " returned by libxl_event_{check,wait}"),
> +    ("domid",    libxl_domid),
> +    ("domuuid",  libxl_uuid),
> +    ("for_user", libxl_ev_user),
> +    ("type",     libxl_event_type),
> +    ("u", KeyedUnion(None, libxl_event_type, "type",
> +          [("domain_shutdown", Struct(None, [
> +                                             ("shutdown_reason", uint8),
> +                                      ])),
> +           ("domain_destroy", Struct(None, [])),
> +           ("disk_eject", Struct(None, [
> +                                        ("vdev", string),
> +                                        ("disk", libxl_device_disk),
> +                                 ])),
> +           ]))])
> +



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