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

[Xen-devel] [PATCH 2/3] RFC: libxl: API changes re event handling



Replace all the existing libxl_event calls and types with a new,
rational scheme.

These are are incompatible changes to the API/ABI.

THIS PATCH IS AN RFC AND SHOULD NOT BE APPLIED.  It contains only the
suggested changes to libxl.h, and not any of the necessary
implementation nor consequential changes.
---
 tools/libxl/libxl.h   |  280 +++++++++++++++++++++++++++++++++++++++++++------
 tools/libxl/libxl.idl |   28 ++++-
 2 files changed, 269 insertions(+), 39 deletions(-)

diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index da878e4..ec20b2a 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -218,6 +218,8 @@ enum {
     ERROR_INVAL = -6,
     ERROR_BADFAIL = -7,
     ERROR_GUEST_TIMEDOUT = -8,
+    ERROR_NOT_READY = -9,
+    ERROR_OSEVENT_REG_FAIL = -10,
 };
 
 #define LIBXL_VERSION 0
@@ -283,7 +285,122 @@ int libxl_run_bootloader(libxl_ctx *ctx,
 
   /* 0 means ERROR_ENOMEM, which we have logged */
 
-/* events handling */
+
+
+/*
+ * 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.
+ */
+
+int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
+                           struct poll *fds, int *timeout_upd);
+  /* app should provide beforepoll with some fds, and give number in *nfds_io.
+   * *nfds_io will in any case be updated according to how many we want.
+   * if space was sufficient, fills in fds[0..<new *nfds_io>]
+   *   and updates *timeout_upd if needed and returns ok.
+   * if space was insufficient, fds[0..<old *nfds_io>] is undefined,
+   *  *timeout_upd may or may not have been updated, returns ERROR_BUFERFULL.
+   */
+void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct poll *fds);
+  /* nfds and fds[0..nfds] must be from _beforepoll as modified by poll
+   */
+
+
+int libxl_osevent_register_hooks(libxl_ctx *ctx, void *user,
+  int (*fd_register)(void *user, int fd, void **for_app_registration_out,
+                     short events, void *for_libxl),
+  int (*fd_modify)(void *user, int fd, void **for_app_registration_update,
+                   short events, void *for_libxl),
+  void (*fd_deregister)(void *user, int fd, void *for_app_registration),
+  void (*timeout_register)(void *user, void **for_app_registration_out,
+                           int milliseconds, void *for_libxl),
+  void (*timeout_modify)(void *user, void **for_app_registration_update,
+                         int milliseconds, void *for_libxl),
+  void (*time_deregister)(void *user, void *for_app_registration_io,
+                          void *for_libxl));
+  /* 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 function 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.
+   *
+   * If it fails 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; when modify fails, any changed
+   * value stored into *for_registration_update is honoured 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 register/modify/deregister from within any libxl
+   * function (indeed, it will usually call register from
+   * register_event_hooks).  Conversely, the application is NOT
+   * PERMITTED to make the event occurrence calls
+   * (libxl_osevent_occurred_*) into libxl reentrantly from
+   * within libxl (for example, from within the register/modify
+   * functions.
+   */
+
+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);
+  /* It is NOT legal to call these functions 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_registerd_call_*.
+   */
+
+
+/*
+ * Domain event handling - getting Xen events from libxl
+ */
+
+
+#define LIBXL_EVENTMASK_ALL (~(unsigned long)0)
 
 typedef struct {
     /* event type */
@@ -293,41 +410,136 @@ typedef struct {
     char *token;
 } libxl_event;
 
-typedef struct {
-    char *path;
-    char *token;
-} libxl_waiter;
+int libxl_event_check(libxl_ctx *ctx, libxl_event *event_r,
+                      unsigned long typemask,
+                      int (*predicate)(const libxl_event*, void *user),
+                      void *predicate_user);
+  /* Searches for an event, already-happened, which matches typemask
+   * and predicate.  predicate==0 matches any event.  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,
+                     int (*predicate)(const libxl_event*, void *user),
+                     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_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);
+int libxl_event_free(libxl_ctx, *ctx, libxl_event *event);
+
+
+/* Alternatively or additionally, the application may also use this: */
+
+void libxl_event_register_callbacks(libxl_ctx *ctx, void *user, uint64_t mask,
+   void (*event_occurs)(void *user, const libxl_event *event),
+   void (*disaster)(void *user, libxl_event_type type,
+                    const char *msg, int errnoval));
+  /*
+   * Arranges that libxl will henceforth call event_occurs for any
+   * events whose type is set in 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
+   * libxl_event_register_callbacks has not been called, errors of
+   * this kind are fatal to the entire application: libxl will print a
+   * message 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.
+   *
+   * 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.  There is only one mask.
+   */
 
-/*
- * 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
+/* Events are only generated if they have been requested.
+ * The following functions request the generation of specific events.
  */
-int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, 
libxl_event *event, libxl_device_disk *disk);
+
+typedef struct libxl_awaiting_domain_death libxl_awaiting_domain_death;
+int libxl_await_domain_death(libxl_ctx *ctx, uint32_t domid, uint64_t user,
+                             libxl_awaiting_domain_death **waiter_out);
+void libxl_noawait_domain_death(libxl_ctx *ctx, uint32_t domid,
+                             libxl_awaiting_domain_death *waiter);
+  /* Generates DOMAIN_SHUTDOWN and DOMAIN_DESTROY events.
+   * A domain which is destroyed before it shuts down generates
+   * only a DESTROY event. */
+
+typedef struct libxl_awaiting_disk_eject libxl_awaiting_disk_eject;
+int libxl_await_disk_eject(libxl_ctx *ctx, uint32_t domid, uint64_t user,
+                           const char *vdev,
+                           libxl_awaiting_disk_eject **waiter_out);
+void int libxl_noawait_disk_eject(libxl_ctx *ctx, uint32_t domid,
+                                  const char *vdev,
+                                  libxl_awaiting_disk_eject *waiter);
+  /* Generates DISK_EJECT events.  vdev will be copied, and will be
+   * returned exactly as the vdev member of event.u. */
+
+
+ /* General rules for event request functions:
+  *
+  * The caller may wait for identical events more than once.  If they
+  * do so, each actual occurrence will generate several events to be
+  * returned by libxl_event_check.  Aside from this, each occurrence
+  * of each event is returned by libxl_event_check exactly once.
+  *
+  * The user value is returned in the generated events and may be
+  * used by the caller for whatever it likes.  Storing a pointer value
+  * in it is permissible.
+  *
+  * If _noawait is called after the event has occurred, the event may
+  * still be returned by libxl_event_check.
+  *
+  * The value "waiter" must be stored by the caller if the caller is
+  * going to call noawait, but may otherwise be ignored.
+  *
+  * If libxl_ctx_free is called, all event generation is cancelled and
+  * it is no longer permissible to call nowait; all "waiter" values
+  * are invalidated by libxl_ctx_free.
+  *
+  * 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 such queued events.
+  */
+
 
 int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
                         const char *old_name, const char *new_name);
diff --git a/tools/libxl/libxl.idl b/tools/libxl/libxl.idl
index 8fb883f..8b285a4 100644
--- a/tools/libxl/libxl.idl
+++ b/tools/libxl/libxl.idl
@@ -73,11 +73,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"),
@@ -371,3 +366,26 @@ 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_event = Struct("event",[
+    ("domid",    libxl_domid),
+    ("domuuid",  libxl_uuid),
+    ("type",     libxl_event_type),
+    ("for_user", uint64),
+    ("u", KeyedUnion(None,"type",
+          [("domain_shutdown", Struct(None, [
+                                             ("shutdown_reason", uint8)
+                                      ])),
+           ("domain_destroy", Struct()),
+           ("disk_eject", Struct(None, [
+                                        ("vdev", string)
+                                        ("disk", libxl_device_disk)
+                                 ])),
+           ]))])
+
-- 
1.5.6.5


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