WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[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