From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
Ian Campbell <ian.campbell@citrix.com>
Subject: [PATCH 13/14] libxl: ao: Cancellation API
Date: Fri, 20 Dec 2013 18:45:51 +0000 [thread overview]
Message-ID: <1387565152-5642-14-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1387565152-5642-1-git-send-email-ian.jackson@eu.citrix.com>
Provide libxl_ao_cancel.
There is machinery to allow an ao to register an interest in its
cancellation, using a libxl__ao_cancellable.
This API is not currently very functional: attempting cancellation it
will always return NOTIMPLEMENTED and have no effect.
Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
---
tools/libxl/libxl.c | 3 ++
tools/libxl/libxl.h | 64 ++++++++++++++++++++++
tools/libxl/libxl_event.c | 122 ++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_internal.h | 42 ++++++++++++++-
4 files changed, 230 insertions(+), 1 deletion(-)
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 0efef98..903dd6e 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -64,6 +64,8 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version,
LIBXL_LIST_INIT(&ctx->evtchns_waiting);
libxl__ev_fd_init(&ctx->evtchn_efd);
+ LIBXL_LIST_INIT(&ctx->aos_inprogress);
+
LIBXL_TAILQ_INIT(&ctx->death_list);
libxl__ev_xswatch_init(&ctx->death_watch);
@@ -161,6 +163,7 @@ int libxl_ctx_free(libxl_ctx *ctx)
assert(LIBXL_LIST_EMPTY(&ctx->efds));
assert(LIBXL_TAILQ_EMPTY(&ctx->etimes));
assert(LIBXL_LIST_EMPTY(&ctx->evtchns_waiting));
+ assert(LIBXL_LIST_EMPTY(&ctx->aos_inprogress));
if (ctx->xch) xc_interface_close(ctx->xch);
libxl_version_info_dispose(&ctx->version_info);
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 784226b..c533ee3 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -409,6 +409,11 @@
*/
#define LIBXL_HAVE_DRIVER_DOMAIN_CREATION 1
+/*
+ * LIBXL_HAVE_AO_CANCEL indicates the availability of libxl_ao_cancel
+ */
+#define LIBXL_HAVE_AO_CANCEL 1
+
/* Functions annotated with LIBXL_EXTERNAL_CALLERS_ONLY may not be
* called from within libxl itself. Callers outside libxl, who
* do not #include libxl_internal.h, are fine. */
@@ -597,6 +602,65 @@ typedef struct {
void *for_callback; /* passed to callback */
} libxl_asyncprogress_how;
+/*
+ * It is sometimes possible to cancel an asynchronous operation.
+ *
+ * libxl_ao_cancel searches for an ongoing asynchronous operation whose
+ * ao_how is identical to *how, and tries to cancel it. The return
+ * values from libxl_ao_cancel are as follows:
+ *
+ * 0
+ *
+ * The operation in question has (at least some) support for
+ * cancellation. It will be cut short. However, it may still
+ * take some time to cancel.
+ *
+ * ERROR_NOTFOUND
+ *
+ * No matching ongoing operation was found. This might happen
+ * for an actual operation if the operation has already completed
+ * (perhaps on another thread). The call to libxl_ao_cancel has
+ * had no effect.
+ *
+ * ERROR_NOTIMPLEMENTED
+ *
+ * As far as could be determined, the operation in question does
+ * not support cancellation. The operation may subsequently
+ * complete normally, as if it had never been cancelled; however,
+ * the cancellation attempt will still have been noted and it is
+ * possible that the operation will be successfully cancelled.
+ *
+ * ERROR_CANCELLED
+ *
+ * The operation has already been the subject of a at least one
+ * call to libxl_ao_cancel.
+ *
+ * If the operation was indeed cut short due to the cancellation, it
+ * will complete, at some point in the future, with ERROR_CANCELLED.
+ * In that case, depending on the operation it have performed some of
+ * the work in question and left the operation half-done. Consult the
+ * documentation for individual operations.
+ *
+ * Note that a cancelled operation might still fail for other reasons
+ * even after it has been cancelled.
+ *
+ * If your application is multithreaded you must not reuse an
+ * ao_how->for_event or ao_how->for_callback value (with a particular
+ * ao_how->callback) unless you are sure that none of your other
+ * threads are going to cancel the previous operation using that
+ * value; otherwise you risk cancelling the wrong operation if the
+ * intended target of the cancellation completes in the meantime.
+ *
+ * It is possible to cancel even an operation which is being performed
+ * synchronously, but since in that case how==NULL you had better only
+ * have one such operation, because it is not possible to tell them
+ * apart. (And, if you want to do this, obviously the cancellation
+ * would have to be requested on a different thread.)
+ */
+int libxl_ao_cancel(libxl_ctx *ctx, const libxl_asyncop_how *how)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+
+
#define LIBXL_VERSION 0
/* context functions */
diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c
index d4e5697..e982858 100644
--- a/tools/libxl/libxl_event.c
+++ b/tools/libxl/libxl_event.c
@@ -1715,6 +1715,7 @@ void libxl__ao_abort(libxl__ao *ao)
assert(ao->in_initiator);
assert(!ao->complete);
assert(!ao->progress_reports_outstanding);
+ assert(!ao->cancelling);
libxl__ao__destroy(CTX, ao);
}
@@ -1874,6 +1875,127 @@ int libxl__ao_inprogress(libxl__ao *ao,
}
+/* cancellation */
+
+static int ao__cancel(libxl_ctx *ctx, libxl__ao *parent)
+{
+ int rc;
+ ao__manip_enter(parent);
+
+ if (parent->cancelling) {
+ rc = ERROR_CANCELLED;
+ goto out;
+ }
+
+ parent->cancelling = 1;
+
+ if (LIBXL_LIST_EMPTY(&parent->cancellables)) {
+ LIBXL__LOG(ctx, XTL_DEBUG,
+ "ao %p: cancellation requested, but not not implemented",
+ parent);
+ rc = ERROR_NOTIMPLEMENTED;
+ goto out;
+ }
+
+ /* We keep calling cancellation hooks until there are none left */
+ while (!LIBXL_LIST_EMPTY(&parent->cancellables)) {
+ libxl__egc egc;
+ LIBXL_INIT_EGC(egc,ctx);
+
+ assert(!parent->complete);
+
+ libxl__ao_cancellable *canc = LIBXL_LIST_FIRST(&parent->cancellables);
+ assert(parent == ao_nested_root(canc->ao));
+
+ LIBXL_LIST_REMOVE(canc, entry);
+ canc->registered = 0;
+
+ LIBXL__LOG(ctx, XTL_DEBUG, "ao %p: canc=%p: cancelling",
+ parent, canc->ao);
+ canc->callback(&egc, canc, ERROR_CANCELLED);
+
+ libxl__ctx_unlock(ctx);
+ libxl__egc_cleanup(&egc);
+ libxl__ctx_lock(ctx);
+ }
+
+ rc = 0;
+
+ out:
+ ao__manip_leave(ctx, parent);
+ return rc;
+}
+
+_hidden int libxl_ao_cancel(libxl_ctx *ctx, const libxl_asyncop_how *how)
+{
+ libxl__ao *search;
+ libxl__ctx_lock(ctx);
+ int rc;
+
+ LIBXL_LIST_FOREACH(search, &ctx->aos_inprogress, inprogress_entry) {
+ if (how) {
+ /* looking for ao to be reported by callback or event */
+ if (search->poller)
+ /* sync */
+ continue;
+ if (how->callback != search->how.callback)
+ continue;
+ if (how->callback
+ ? (how->u.for_callback != search->how.u.for_callback)
+ : (how->u.for_event != search->how.u.for_event))
+ continue;
+ } else {
+ /* looking for synchronous call */
+ if (!search->poller)
+ /* async */
+ continue;
+ }
+ goto found;
+ }
+ rc = ERROR_NOTFOUND;
+ goto out;
+
+ found:
+ rc = ao__cancel(ctx, search);
+ out:
+ libxl__ctx_unlock(ctx);
+ return rc;
+}
+
+int libxl__ao_cancellable_register(libxl__ao_cancellable *canc)
+{
+ libxl__ao *ao = canc->ao;
+ libxl__ao *root = ao_nested_root(ao);
+ AO_GC;
+
+ if (root->cancelling) {
+ DBG("ao=%p: preemptively cancelling cancellable registration %p (root=%p)",
+ ao, canc, root);
+ return ERROR_CANCELLED;
+ }
+
+ DBG("ao=%p, canc=%p: registering (root=%p)", ao, canc, root);
+ LIBXL_LIST_INSERT_HEAD(&root->cancellables, canc, entry);
+ canc->registered = 1;
+
+ return 0;
+}
+
+_hidden void libxl__ao_cancellable_deregister(libxl__ao_cancellable *canc)
+{
+ if (!canc->registered)
+ return;
+
+ libxl__ao *ao = canc->ao;
+ libxl__ao *root __attribute__((unused)) = ao_nested_root(ao);
+ AO_GC;
+
+ DBG("ao=%p, canc=%p: deregistering (root=%p)", ao, canc, root);
+ LIBXL_LIST_REMOVE(canc, entry);
+ canc->registered = 0;
+}
+
+
/* progress reporting */
/* The application indicates a desire to ignore events by passing NULL
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index bb239ac..951a77d 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -170,6 +170,41 @@ struct libxl__ev_fd {
};
+typedef struct libxl__ao_cancellable libxl__ao_cancellable;
+typedef void libxl__ao_cancellable_callback(libxl__egc *egc,
+ libxl__ao_cancellable *cancellable, int rc /* CANCELLED */);
+
+struct libxl__ao_cancellable {
+ /* caller must fill this in and it must remain valid */
+ libxl__ao *ao;
+ libxl__ao_cancellable_callback *callback;
+ /* remainder is private for cancellation machinery */
+ bool registered;
+ LIBXL_LIST_ENTRY(libxl__ao_cancellable) entry;
+ /*
+ * For nested aos:
+ * Semantically, cancellation affects the whole tree of aos,
+ * not just the parent.
+ * libxl__ao_cancellable.ao refers to the child, so
+ * that the child callback sees the right ao. (After all,
+ * it was code dealing with the child that set .ao.)
+ * But, the cancellable is recorded on the "cancellables" list
+ * for the ultimate root ao, so that every possible child
+ * cancellation occurs as a result of the cancellation of the
+ * parent.
+ * We set ao->cancelling only in the root.
+ */
+};
+
+_hidden int libxl__ao_cancellable_register(libxl__ao_cancellable*);
+_hidden void libxl__ao_cancellable_deregister(libxl__ao_cancellable*);
+
+static inline void libxl__ao_cancellable_init
+ (libxl__ao_cancellable *c) { c->registered = 0; }
+static inline bool libxl__ao_cancellable_isregistered
+ (const libxl__ao_cancellable *c) { return c->registered; }
+
+
typedef struct libxl__ev_time libxl__ev_time;
typedef void libxl__ev_time_callback(libxl__egc *egc, libxl__ev_time *ev,
const struct timeval *requested_abs,
@@ -359,6 +394,8 @@ struct libxl__ctx {
LIBXL_LIST_HEAD(, libxl__ev_evtchn) evtchns_waiting;
libxl__ev_fd evtchn_efd;
+ LIBXL_LIST_HEAD(, libxl__ao) aos_inprogress;
+
LIBXL_TAILQ_HEAD(libxl__evgen_domain_death_list, libxl_evgen_domain_death)
death_list /* sorted by domid */,
death_reported;
@@ -443,12 +480,15 @@ struct libxl__ao {
* only in libxl__ao_complete.)
*/
uint32_t magic;
- unsigned constructing:1, in_initiator:1, complete:1, notified:1;
+ unsigned constructing:1, in_initiator:1, complete:1, notified:1,
+ cancelling:1;
int manip_refcnt;
libxl__ao *nested_root;
int nested_progeny;
int progress_reports_outstanding;
int rc;
+ LIBXL_LIST_HEAD(, libxl__ao_cancellable) cancellables;
+ LIBXL_LIST_ENTRY(libxl__ao) inprogress_entry;
libxl__gc gc;
libxl_asyncop_how how;
libxl__poller *poller;
--
1.7.10.4
next prev parent reply other threads:[~2013-12-20 18:45 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <4B8F5D33B081C044AA43634E84ED7F9616A83D@AMSPEX01CL03.citrite.net>
2013-10-23 17:23 ` FW: Cancelling asynchronous operations in libxl Konrad Rzeszutek Wilk
2013-10-26 8:33 ` Ian Campbell
[not found] ` <1382776392.22417.179.camel@hastur.hellion.org.uk>
2013-10-28 9:38 ` Simon Beaumont
2013-10-28 15:52 ` Ian Jackson
2013-10-31 13:52 ` Ian Campbell
2013-10-31 14:32 ` Ian Jackson
2013-10-31 17:09 ` Ian Campbell
2013-11-08 18:38 ` Ian Jackson
2013-11-20 11:01 ` Ian Campbell
2013-12-20 18:24 ` Ian Jackson
2013-12-20 18:45 ` [RFC PATCH 00/14] libxl: Asynchronous event cancellation Ian Jackson
2013-12-20 18:45 ` [PATCH 01/14] libxl: suspend: switch_logdirty_done takes rc Ian Jackson
2013-12-20 18:45 ` [PATCH 02/14] libxl: suspend: common suspend callbacks take rc Ian Jackson
2013-12-20 18:45 ` [PATCH 03/14] libxl: suspend: Return correct error from callbacks Ian Jackson
2013-12-20 18:45 ` [PATCH 04/14] libxl: Use libxl__xswait* in libxl__ao_device Ian Jackson
2013-12-20 18:45 ` [PATCH 05/14] libxl: xswait/devstate: Move xswait to before devstate Ian Jackson
2013-12-20 18:45 ` [PATCH 06/14] libxl: devstate: Use libxl__xswait* Ian Jackson
2013-12-20 18:45 ` [PATCH 07/14] libxl: New error codes CANCELLED etc Ian Jackson
2013-12-20 18:45 ` [PATCH 08/14] libxl: events: Permit timeouts to signal cancellation Ian Jackson
2013-12-20 18:45 ` [PATCH 09/14] libxl: domain create: Do not destroy on cancellation Ian Jackson
2013-12-20 18:45 ` [PATCH 10/14] libxl: ao: Record ultimate parent of a nested ao Ian Jackson
2013-12-20 18:45 ` [PATCH 11/14] libxl: ao: Count the nested progeny of an ao Ian Jackson
2013-12-20 18:45 ` [PATCH 12/14] libxl: ao: Provide manip_refcnt Ian Jackson
2013-12-20 18:45 ` Ian Jackson [this message]
2013-12-20 18:45 ` [PATCH 14/14] libxl: ao: Timeouts are cancellable Ian Jackson
2014-03-14 10:42 ` FW: Cancelling asynchronous operations in libxl Ian Campbell
2014-03-14 12:32 ` Simon Beaumont
2014-03-14 17:09 ` Ian Jackson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1387565152-5642-14-git-send-email-ian.jackson@eu.citrix.com \
--to=ian.jackson@eu.citrix.com \
--cc=ian.campbell@citrix.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).