aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxl/libxl_event.c
diff options
context:
space:
mode:
authorIan Jackson <ian.jackson@eu.citrix.com>2012-05-11 18:59:05 +0100
committerIan Jackson <ian.jackson@eu.citrix.com>2012-05-11 18:59:05 +0100
commit254a9c4a28e9d35426bb098a2d52c035b8f1e416 (patch)
tree20bf0ef4edb229b13c6915d3aa66ec422bbbd765 /tools/libxl/libxl_event.c
parent738b3d44252221ed3be1a860366a15a2d1b9b091 (diff)
downloadxen-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.c72
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