qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PULL 11/14] aio: add .io_poll_begin/end() callbacks
Date: Wed,  4 Jan 2017 13:34:11 +0000	[thread overview]
Message-ID: <20170104133414.6524-12-stefanha@redhat.com> (raw)
In-Reply-To: <20170104133414.6524-1-stefanha@redhat.com>

The begin and end callbacks can be used to prepare for the polling loop
and clean up when polling stops.  Note that they may only be called once
for multiple aio_poll() calls if polling continues to succeed.  Once
polling fails the end callback is invoked before aio_poll() resumes file
descriptor monitoring.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 20161201192652.9509-11-stefanha@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/block/aio.h |  20 ++++++++++
 aio-posix.c         | 105 ++++++++++++++++++++++++++++++++++++++++++++--------
 aio-win32.c         |  15 ++++++++
 3 files changed, 125 insertions(+), 15 deletions(-)

diff --git a/include/block/aio.h b/include/block/aio.h
index 349143f..3817d17 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -137,6 +137,9 @@ struct AioContext {
     /* Maximum polling time in nanoseconds */
     int64_t poll_max_ns;
 
+    /* Are we in polling mode or monitoring file descriptors? */
+    bool poll_started;
+
     /* epoll(7) state used when built with CONFIG_EPOLL */
     int epollfd;
     bool epoll_enabled;
@@ -339,6 +342,14 @@ void aio_set_fd_handler(AioContext *ctx,
                         AioPollFn *io_poll,
                         void *opaque);
 
+/* Set polling begin/end callbacks for a file descriptor that has already been
+ * registered with aio_set_fd_handler.  Do nothing if the file descriptor is
+ * not registered.
+ */
+void aio_set_fd_poll(AioContext *ctx, int fd,
+                     IOHandler *io_poll_begin,
+                     IOHandler *io_poll_end);
+
 /* Register an event notifier and associated callbacks.  Behaves very similarly
  * to event_notifier_set_handler.  Unlike event_notifier_set_handler, these callbacks
  * will be invoked when using aio_poll().
@@ -352,6 +363,15 @@ void aio_set_event_notifier(AioContext *ctx,
                             EventNotifierHandler *io_read,
                             AioPollFn *io_poll);
 
+/* Set polling begin/end callbacks for an event notifier that has already been
+ * registered with aio_set_event_notifier.  Do nothing if the event notifier is
+ * not registered.
+ */
+void aio_set_event_notifier_poll(AioContext *ctx,
+                                 EventNotifier *notifier,
+                                 EventNotifierHandler *io_poll_begin,
+                                 EventNotifierHandler *io_poll_end);
+
 /* Return a GSource that lets the main loop poll the file descriptors attached
  * to this AioContext.
  */
diff --git a/aio-posix.c b/aio-posix.c
index c6adddb..5216d82 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -30,6 +30,8 @@ struct AioHandler
     IOHandler *io_read;
     IOHandler *io_write;
     AioPollFn *io_poll;
+    IOHandler *io_poll_begin;
+    IOHandler *io_poll_end;
     int deleted;
     void *opaque;
     bool is_external;
@@ -270,6 +272,20 @@ void aio_set_fd_handler(AioContext *ctx,
     }
 }
 
+void aio_set_fd_poll(AioContext *ctx, int fd,
+                     IOHandler *io_poll_begin,
+                     IOHandler *io_poll_end)
+{
+    AioHandler *node = find_aio_handler(ctx, fd);
+
+    if (!node) {
+        return;
+    }
+
+    node->io_poll_begin = io_poll_begin;
+    node->io_poll_end = io_poll_end;
+}
+
 void aio_set_event_notifier(AioContext *ctx,
                             EventNotifier *notifier,
                             bool is_external,
@@ -280,8 +296,53 @@ void aio_set_event_notifier(AioContext *ctx,
                        (IOHandler *)io_read, NULL, io_poll, notifier);
 }
 
+void aio_set_event_notifier_poll(AioContext *ctx,
+                                 EventNotifier *notifier,
+                                 EventNotifierHandler *io_poll_begin,
+                                 EventNotifierHandler *io_poll_end)
+{
+    aio_set_fd_poll(ctx, event_notifier_get_fd(notifier),
+                    (IOHandler *)io_poll_begin,
+                    (IOHandler *)io_poll_end);
+}
+
+static void poll_set_started(AioContext *ctx, bool started)
+{
+    AioHandler *node;
+
+    if (started == ctx->poll_started) {
+        return;
+    }
+
+    ctx->poll_started = started;
+
+    ctx->walking_handlers++;
+    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+        IOHandler *fn;
+
+        if (node->deleted) {
+            continue;
+        }
+
+        if (started) {
+            fn = node->io_poll_begin;
+        } else {
+            fn = node->io_poll_end;
+        }
+
+        if (fn) {
+            fn(node->opaque);
+        }
+    }
+    ctx->walking_handlers--;
+}
+
+
 bool aio_prepare(AioContext *ctx)
 {
+    /* Poll mode cannot be used with glib's event loop, disable it. */
+    poll_set_started(ctx, false);
+
     return false;
 }
 
@@ -422,6 +483,23 @@ static void add_pollfd(AioHandler *node)
     npfd++;
 }
 
+static bool run_poll_handlers_once(AioContext *ctx)
+{
+    bool progress = false;
+    AioHandler *node;
+
+    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+        if (!node->deleted && node->io_poll &&
+                node->io_poll(node->opaque)) {
+            progress = true;
+        }
+
+        /* Caller handles freeing deleted nodes.  Don't do it here. */
+    }
+
+    return progress;
+}
+
 /* run_poll_handlers:
  * @ctx: the AioContext
  * @max_ns: maximum time to poll for, in nanoseconds
@@ -437,7 +515,7 @@ static void add_pollfd(AioHandler *node)
  */
 static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
 {
-    bool progress = false;
+    bool progress;
     int64_t end_time;
 
     assert(ctx->notify_me);
@@ -449,16 +527,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
     end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns;
 
     do {
-        AioHandler *node;
-
-        QLIST_FOREACH(node, &ctx->aio_handlers, node) {
-            if (!node->deleted && node->io_poll &&
-                node->io_poll(node->opaque)) {
-                progress = true;
-            }
-
-            /* Caller handles freeing deleted nodes.  Don't do it here. */
-        }
+        progress = run_poll_handlers_once(ctx);
     } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);
 
     trace_run_poll_handlers_end(ctx, progress);
@@ -468,10 +537,9 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
 
 /* try_poll_mode:
  * @ctx: the AioContext
- * @blocking: polling is only attempted when blocking is true
+ * @blocking: busy polling is only attempted when blocking is true
  *
- * If blocking is true then ctx->notify_me must be non-zero so this function
- * can detect aio_notify().
+ * ctx->notify_me must be non-zero so this function can detect aio_notify().
  *
  * Note that the caller must have incremented ctx->walking_handlers.
  *
@@ -485,13 +553,20 @@ static bool try_poll_mode(AioContext *ctx, bool blocking)
                              (uint64_t)ctx->poll_max_ns);
 
         if (max_ns) {
+            poll_set_started(ctx, true);
+
             if (run_poll_handlers(ctx, max_ns)) {
                 return true;
             }
         }
     }
 
-    return false;
+    poll_set_started(ctx, false);
+
+    /* Even if we don't run busy polling, try polling once in case it can make
+     * progress and the caller will be able to avoid ppoll(2)/epoll_wait(2).
+     */
+    return run_poll_handlers_once(ctx);
 }
 
 bool aio_poll(AioContext *ctx, bool blocking)
diff --git a/aio-win32.c b/aio-win32.c
index 0a6e91b..d0e40a8 100644
--- a/aio-win32.c
+++ b/aio-win32.c
@@ -102,6 +102,13 @@ void aio_set_fd_handler(AioContext *ctx,
     aio_notify(ctx);
 }
 
+void aio_set_fd_poll(AioContext *ctx, int fd,
+                     IOHandler *io_poll_begin,
+                     IOHandler *io_poll_end)
+{
+    /* Not implemented */
+}
+
 void aio_set_event_notifier(AioContext *ctx,
                             EventNotifier *e,
                             bool is_external,
@@ -153,6 +160,14 @@ void aio_set_event_notifier(AioContext *ctx,
     aio_notify(ctx);
 }
 
+void aio_set_event_notifier_poll(AioContext *ctx,
+                                 EventNotifier *notifier,
+                                 EventNotifierHandler *io_poll_begin,
+                                 EventNotifierHandler *io_poll_end)
+{
+    /* Not implemented */
+}
+
 bool aio_prepare(AioContext *ctx)
 {
     static struct timeval tv0;
-- 
2.9.3

  parent reply	other threads:[~2017-01-04 13:34 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-04 13:34 [Qemu-devel] [PULL 00/14] Block patches Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 01/14] HACKING: document #include order Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 02/14] aio: add flag to skip fds to aio_dispatch() Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 03/14] aio: add AioPollFn and io_poll() interface Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 04/14] aio: add polling mode to AioContext Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 05/14] virtio: poll virtqueues for new buffers Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 06/14] linux-aio: poll ring for completions Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 07/14] iothread: add polling parameters Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 08/14] virtio-blk: suppress virtqueue kick during processing Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 09/14] virtio-scsi: " Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 10/14] virtio: turn vq->notification into a nested counter Stefan Hajnoczi
2017-01-04 13:34 ` Stefan Hajnoczi [this message]
2017-01-04 13:34 ` [Qemu-devel] [PULL 12/14] virtio: disable virtqueue notifications during polling Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 13/14] aio: self-tune polling time Stefan Hajnoczi
2017-01-04 13:34 ` [Qemu-devel] [PULL 14/14] iothread: add poll-grow and poll-shrink parameters Stefan Hajnoczi
2017-01-05 13:57 ` [Qemu-devel] [PULL 00/14] Block patches Peter Maydell

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=20170104133414.6524-12-stefanha@redhat.com \
    --to=stefanha@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /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).