[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |