diff options
author | Ian Jackson <ian.jackson@eu.citrix.com> | 2012-05-11 18:59:05 +0100 |
---|---|---|
committer | Ian Jackson <ian.jackson@eu.citrix.com> | 2012-05-11 18:59:05 +0100 |
commit | 254a9c4a28e9d35426bb098a2d52c035b8f1e416 (patch) | |
tree | 20bf0ef4edb229b13c6915d3aa66ec422bbbd765 /tools/libxl/libxl_event.c | |
parent | 738b3d44252221ed3be1a860366a15a2d1b9b091 (diff) | |
download | xen-254a9c4a28e9d35426bb098a2d52c035b8f1e416.tar.gz xen-254a9c4a28e9d35426bb098a2d52c035b8f1e416.tar.bz2 xen-254a9c4a28e9d35426bb098a2d52c035b8f1e416.zip |
libxl: provide progress reporting for long-running operations
This will be used for reporting, during domain creation, that the
console is ready.
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Changes since v7:
* If aop->how.callback, actually add the aop to the for_callback list (!)
* Document the threadsafety of aop's, and make appropriate cross-references.
* Allocate the actual aop from its thread's egc; do not free it.
* Remove pointless code motion of libxl__ao_create.
* Minor formatting fixes.
Committed-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
Diffstat (limited to 'tools/libxl/libxl_event.c')
-rw-r--r-- | tools/libxl/libxl_event.c | 72 |
1 files changed, 69 insertions, 3 deletions
diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c index b546471a0d..460ef66b6f 100644 --- a/tools/libxl/libxl_event.c +++ b/tools/libxl/libxl_event.c @@ -902,18 +902,29 @@ void libxl__event_disaster(libxl__egc *egc, const char *msg, int errnoval, static void egc_run_callbacks(libxl__egc *egc) { /* - * The callbacks must happen with the ctx unlocked. - * See the comment near #define EGC_GC in libxl_internal.h and - * those in the definitions of libxl__egc and libxl__ao. + * The callbacks must happen with the ctx unlocked. See the + * comment near #define EGC_GC in libxl_internal.h and those in + * the definitions of libxl__egc, libxl__ao and libxl__aop. */ EGC_GC; libxl_event *ev, *ev_tmp; + libxl__aop_occurred *aop, *aop_tmp; LIBXL_TAILQ_FOREACH_SAFE(ev, &egc->occurred_for_callback, link, ev_tmp) { LIBXL_TAILQ_REMOVE(&egc->occurred_for_callback, ev, link); CTX->event_hooks->event_occurs(CTX->event_hooks_user, ev); } + LIBXL_TAILQ_FOREACH_SAFE(aop, &egc->aops_for_callback, entry, aop_tmp) { + LIBXL_TAILQ_REMOVE(&egc->aops_for_callback, aop, entry); + aop->how->callback(CTX, aop->ev, aop->how->for_callback); + + CTX_LOCK; + aop->ao->progress_reports_outstanding--; + libxl__ao_complete_check_progress_reports(egc, aop->ao); + CTX_UNLOCK; + } + libxl__ao *ao, *ao_tmp; LIBXL_TAILQ_FOREACH_SAFE(ao, &egc->aos_for_callback, entry_for_callback, ao_tmp) { @@ -1296,6 +1307,7 @@ void libxl__ao_abort(libxl__ao *ao) assert(ao->magic == LIBXL__AO_MAGIC); assert(ao->in_initiator); assert(!ao->complete); + assert(!ao->progress_reports_outstanding); libxl__ao__destroy(CTX, ao); } @@ -1306,6 +1318,24 @@ void libxl__ao_complete(libxl__egc *egc, libxl__ao *ao, int rc) ao->complete = 1; ao->rc = rc; + libxl__ao_complete_check_progress_reports(egc, ao); +} + +void libxl__ao_complete_check_progress_reports(libxl__egc *egc, libxl__ao *ao) +{ + /* + * We don't consider an ao complete if it has any outstanding + * callbacks. These callbacks might be outstanding on other + * threads, queued up in the other threads' egc's. Those threads + * will, after making the callback, take out the lock again, + * decrement progress_reports_outstanding, and call us again. + */ + + assert(ao->progress_reports_outstanding >= 0); + + if (!ao->complete || ao->progress_reports_outstanding) + return; + if (ao->poller) { assert(ao->in_initiator); if (!ao->constructing) @@ -1355,6 +1385,7 @@ libxl__ao *libxl__ao_create(libxl_ctx *ctx, uint32_t domid, return NULL; } + int libxl__ao_inprogress(libxl__ao *ao) { AO_GC; @@ -1412,6 +1443,41 @@ int libxl__ao_inprogress(libxl__ao *ao) } +/* progress reporting */ + +/* The application indicates a desire to ignore events by passing NULL + * for how. But we want to copy *how. So we have this dummy function + * whose address is stored in callback if the app passed how==NULL. */ +static void dummy_asyncprogress_callback_ignore + (libxl_ctx *ctx, libxl_event *ev, void *for_callback) { } + +void libxl__ao_progress_gethow(libxl_asyncprogress_how *in_state, + const libxl_asyncprogress_how *from_app) { + if (from_app) + *in_state = *from_app; + else + in_state->callback = dummy_asyncprogress_callback_ignore; +} + +void libxl__ao_progress_report(libxl__egc *egc, libxl__ao *ao, + const libxl_asyncprogress_how *how, libxl_event *ev) +{ + ev->for_user = how->for_event; + if (how->callback == dummy_asyncprogress_callback_ignore) { + /* ignore */ + } else if (how->callback) { + libxl__aop_occurred *aop = libxl__zalloc(&egc->gc, sizeof(*aop)); + ao->progress_reports_outstanding++; + aop->ao = ao; + aop->ev = ev; + aop->how = how; + LIBXL_TAILQ_INSERT_TAIL(&egc->aops_for_callback, aop, entry); + } else { + libxl__event_occurred(egc, ev); + } +} + + /* * Local variables: * mode: C |