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
|