All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
	Euan Harris <euan.harris@citrix.com>
Subject: [PATCH 17/29] libxl: cancellation: Provide public ao cancellation API
Date: Tue, 10 Feb 2015 20:10:04 +0000	[thread overview]
Message-ID: <1423599016-32639-18-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1423599016-32639-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>
---
v2: Minor comment improvements
---
 tools/libxl/libxl.c          |    3 ++
 tools/libxl/libxl.h          |   64 ++++++++++++++++++++++
 tools/libxl/libxl_event.c    |  123 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_internal.h |   42 ++++++++++++++-
 4 files changed, 231 insertions(+), 1 deletion(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index ae0c7e1..193493b 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -73,6 +73,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);
 
@@ -174,6 +176,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 9385e82..e8a2a91 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -642,6 +642,11 @@ typedef struct libxl__ctx libxl_ctx;
  */
 #define LIBXL_HAVE_DEVICE_CHANNEL 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. */
@@ -904,6 +909,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 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 80677e0..55013ef 100644
--- a/tools/libxl/libxl_event.c
+++ b/tools/libxl/libxl_event.c
@@ -1773,6 +1773,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);
 }
 
@@ -1938,6 +1939,128 @@ int libxl__ao_inprogress(libxl__ao *ao,
 }
 
 
+/* cancellation */
+
+static int ao__cancel(libxl_ctx *ctx, libxl__ao *parent)
+/* Temporarily unlocks ctx, which must be locked exactly once on entry. */
+{
+    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 d2c2637..46383c4 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -173,6 +173,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,
@@ -362,6 +397,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;
@@ -448,12 +485,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

  parent reply	other threads:[~2015-02-10 20:10 UTC|newest]

Thread overview: 98+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-10 20:09 [RFC PATCH v2 00/29] libxl: Cancelling asynchronous operations Ian Jackson
2015-02-10 20:09 ` [PATCH 01/29] libxl: Further fix exit paths from libxl_device_events_handler Ian Jackson
2015-02-18 16:23   ` Roger Pau Monné
2015-03-24 10:49     ` Ian Campbell
2015-02-10 20:09 ` [PATCH 02/29] libxl: Comment cleanups Ian Jackson
2015-02-11  1:46   ` Hongyang Yang
2015-02-11 12:05     ` Ian Jackson
2015-03-30  9:08     ` Ian Campbell
2015-03-24 10:50   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 03/29] libxl: suspend: switch_logdirty_done takes rc Ian Jackson
2015-03-24 10:53   ` Ian Campbell
2015-03-31 18:02     ` Ian Jackson
2015-02-10 20:09 ` [PATCH 04/29] libxl: suspend: common suspend callbacks take rc Ian Jackson
2015-03-24 10:55   ` Ian Campbell
2015-03-31 18:03     ` Ian Jackson
2015-02-10 20:09 ` [PATCH 05/29] libxl: suspend: Return correct error from callbacks Ian Jackson
2015-03-24 10:58   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 06/29] libxl: Use libxl__xswait* in libxl__ao_device Ian Jackson
2015-03-24 11:04   ` Ian Campbell
2015-03-31 18:06     ` Ian Jackson
2015-04-01  9:25       ` Ian Campbell
2015-02-10 20:09 ` [PATCH 07/29] libxl: xswait/devstate: Move xswait to before devstate Ian Jackson
2015-03-24 11:05   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 08/29] libxl: devstate: Use libxl__xswait* Ian Jackson
2015-03-24 11:07   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 09/29] libxl: New error codes CANCELLED etc Ian Jackson
2015-03-24 11:08   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 10/29] libxl: events: Make timeout and async exec setup take an ao, not a gc Ian Jackson
2015-02-11  1:04   ` Wen Congyang
2015-02-11 12:04     ` Ian Jackson
2015-03-31 18:09     ` Ian Jackson
2015-03-24 11:09   ` Ian Campbell
2015-02-10 20:09 ` [PATCH 11/29] libxl: events: Make libxl__async_exec_* pass caller an rc Ian Jackson
2015-03-24 11:20   ` Ian Campbell
2015-03-31 18:12     ` Ian Jackson
2015-04-01  9:29       ` Ian Campbell
2015-02-10 20:09 ` [PATCH 12/29] libxl: events: Permit timeouts to signal cancellation Ian Jackson
2015-03-24 11:22   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 13/29] libxl: domain create: Do not destroy on cancellation Ian Jackson
2015-03-24 11:24   ` Ian Campbell
2015-03-31 18:14     ` Ian Jackson
2015-02-10 20:10 ` [PATCH 14/29] libxl: ao: Record ultimate parent of a nested ao Ian Jackson
2015-03-24 11:26   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 15/29] libxl: ao: Count the nested progeny of an ao Ian Jackson
2015-03-24 11:27   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 16/29] libxl: ao: Provide manip_refcnt Ian Jackson
2015-03-24 11:32   ` Ian Campbell
2015-03-31 18:23     ` Ian Jackson
2015-04-01  9:34       ` Ian Campbell
2015-02-10 20:10 ` Ian Jackson [this message]
2015-03-24 11:45   ` [PATCH 17/29] libxl: cancellation: Provide public ao cancellation API Ian Campbell
2015-03-31 18:26     ` Ian Jackson
2015-03-24 11:48   ` Ian Campbell
2015-03-31 18:33     ` Ian Jackson
2015-04-01  9:38       ` Ian Campbell
2015-02-10 20:10 ` [PATCH 18/29] libxl: cancellation: Provide explicit internal cancel check API Ian Jackson
2015-03-24 11:45   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 19/29] libxl: cancellation: Make timeouts cancellable Ian Jackson
2015-03-24 11:50   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 20/29] libxl: cancellation: Note that driver domain task cannot be usefully cancelled Ian Jackson
2015-02-18 16:24   ` Roger Pau Monné
2015-03-24 11:51   ` Ian Campbell
2015-03-31 18:37     ` Ian Jackson
2015-02-10 20:10 ` [PATCH 21/29] libxl: cancellation: Make spawns cancellable Ian Jackson
2015-03-24 11:53   ` Ian Campbell
2015-03-31 18:45     ` Ian Jackson
2015-04-01  9:40       ` Ian Campbell
2015-02-10 20:10 ` [PATCH 22/29] libxl: Introduce DOMAIN_DESTROYED error code Ian Jackson
2015-03-24 11:56   ` Ian Campbell
2015-03-31 18:47     ` Ian Jackson
2015-04-01  9:41       ` Ian Campbell
2015-02-10 20:10 ` [PATCH 23/29] libxl: cancellation: Support cancellation where we spot domain death Ian Jackson
2015-03-24 11:58   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 24/29] libxl: Introduce FILLZERO Ian Jackson
2015-03-24 12:03   ` Ian Campbell
2015-03-31 18:51     ` Ian Jackson
2015-04-01  9:42       ` Ian Campbell
2015-02-10 20:10 ` [PATCH 25/29] libxl: cancellation: Preparations for save/restore cancellation Ian Jackson
2015-03-24 12:04   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 26/29] libxl: cancellation: Handle SIGTERM in save/restore helper Ian Jackson
2015-03-24 12:07   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 27/29] libxl: cancellation: Cancel libxc save/restore Ian Jackson
2015-03-24 12:08   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 28/29] libxl: ao: datacopier callback gets an rc Ian Jackson
2015-03-24 12:10   ` Ian Campbell
2015-02-10 20:10 ` [PATCH 29/29] libxl: cancellation: Make datacopiers cancellable Ian Jackson
2015-03-24 12:11   ` Ian Campbell
2015-02-10 20:13 ` [RFC PATCH v2 00/29] libxl: Cancelling asynchronous operations Ian Jackson
2015-02-18 16:10 ` Euan Harris
2015-02-18 16:12   ` Ian Jackson
2015-04-07 17:08   ` Euan Harris
2015-04-07 17:19     ` Ian Jackson
2015-04-09 16:44       ` Euan Harris
2015-04-09 16:50         ` Ian Jackson
2015-04-14  9:43       ` Euan Harris
2015-03-03 12:08 ` Ian Campbell
2015-03-20 10:39   ` Euan Harris
2015-04-07 17:22   ` 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=1423599016-32639-18-git-send-email-ian.jackson@eu.citrix.com \
    --to=ian.jackson@eu.citrix.com \
    --cc=euan.harris@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.