[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 13/76] aio-posix: move pollfds to thread-local storag
From: |
Kevin Wolf |
Subject: |
[Qemu-devel] [PULL 13/76] aio-posix: move pollfds to thread-local storage |
Date: |
Tue, 28 Apr 2015 16:59:55 +0200 |
From: Paolo Bonzini <address@hidden>
By using thread-local storage, aio_poll can stop using global data during
g_poll_ns. This will make it possible to drop callbacks from rfifolock.
[Moved npfd = 0 assignment to end of walking_handlers region as
suggested by Paolo. This resolves the assert(npfd == 0) assertion
failure in pollfds_cleanup().
--Stefan]
Signed-off-by: Paolo Bonzini <address@hidden>
Reviewed-by: Stefan Hajnoczi <address@hidden>
Message-id: address@hidden
Signed-off-by: Stefan Hajnoczi <address@hidden>
Signed-off-by: Kevin Wolf <address@hidden>
---
aio-posix.c | 78 ++++++++++++++++++++++++++++++++++++++---------------
async.c | 2 --
include/block/aio.h | 3 ---
3 files changed, 57 insertions(+), 26 deletions(-)
diff --git a/aio-posix.c b/aio-posix.c
index cbd4c34..296cd9b 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -24,7 +24,6 @@ struct AioHandler
IOHandler *io_read;
IOHandler *io_write;
int deleted;
- int pollfds_idx;
void *opaque;
QLIST_ENTRY(AioHandler) node;
};
@@ -83,7 +82,6 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_read = io_read;
node->io_write = io_write;
node->opaque = opaque;
- node->pollfds_idx = -1;
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
@@ -186,12 +184,59 @@ bool aio_dispatch(AioContext *ctx)
return progress;
}
+/* These thread-local variables are used only in a small part of aio_poll
+ * around the call to the poll() system call. In particular they are not
+ * used while aio_poll is performing callbacks, which makes it much easier
+ * to think about reentrancy!
+ *
+ * Stack-allocated arrays would be perfect but they have size limitations;
+ * heap allocation is expensive enough that we want to reuse arrays across
+ * calls to aio_poll(). And because poll() has to be called without holding
+ * any lock, the arrays cannot be stored in AioContext. Thread-local data
+ * has none of the disadvantages of these three options.
+ */
+static __thread GPollFD *pollfds;
+static __thread AioHandler **nodes;
+static __thread unsigned npfd, nalloc;
+static __thread Notifier pollfds_cleanup_notifier;
+
+static void pollfds_cleanup(Notifier *n, void *unused)
+{
+ g_assert(npfd == 0);
+ g_free(pollfds);
+ g_free(nodes);
+ nalloc = 0;
+}
+
+static void add_pollfd(AioHandler *node)
+{
+ if (npfd == nalloc) {
+ if (nalloc == 0) {
+ pollfds_cleanup_notifier.notify = pollfds_cleanup;
+ qemu_thread_atexit_add(&pollfds_cleanup_notifier);
+ nalloc = 8;
+ } else {
+ g_assert(nalloc <= INT_MAX);
+ nalloc *= 2;
+ }
+ pollfds = g_renew(GPollFD, pollfds, nalloc);
+ nodes = g_renew(AioHandler *, nodes, nalloc);
+ }
+ nodes[npfd] = node;
+ pollfds[npfd] = (GPollFD) {
+ .fd = node->pfd.fd,
+ .events = node->pfd.events,
+ };
+ npfd++;
+}
+
bool aio_poll(AioContext *ctx, bool blocking)
{
AioHandler *node;
bool was_dispatching;
- int ret;
+ int i, ret;
bool progress;
+ int64_t timeout;
was_dispatching = ctx->dispatching;
progress = false;
@@ -210,39 +255,30 @@ bool aio_poll(AioContext *ctx, bool blocking)
ctx->walking_handlers++;
- g_array_set_size(ctx->pollfds, 0);
+ assert(npfd == 0);
/* fill pollfds */
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
- node->pollfds_idx = -1;
if (!node->deleted && node->pfd.events) {
- GPollFD pfd = {
- .fd = node->pfd.fd,
- .events = node->pfd.events,
- };
- node->pollfds_idx = ctx->pollfds->len;
- g_array_append_val(ctx->pollfds, pfd);
+ add_pollfd(node);
}
}
- ctx->walking_handlers--;
+ timeout = blocking ? aio_compute_timeout(ctx) : 0;
/* wait until next event */
- ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
- ctx->pollfds->len,
- blocking ? aio_compute_timeout(ctx) : 0);
+ ret = qemu_poll_ns((GPollFD *)pollfds, npfd, timeout);
/* if we have any readable fds, dispatch event */
if (ret > 0) {
- QLIST_FOREACH(node, &ctx->aio_handlers, node) {
- if (node->pollfds_idx != -1) {
- GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
- node->pollfds_idx);
- node->pfd.revents = pfd->revents;
- }
+ for (i = 0; i < npfd; i++) {
+ nodes[i]->pfd.revents = pollfds[i].revents;
}
}
+ npfd = 0;
+ ctx->walking_handlers--;
+
/* Run dispatch even if there were no readable fds to run timers */
aio_set_dispatching(ctx, true);
if (aio_dispatch(ctx)) {
diff --git a/async.c b/async.c
index 2b51e87..77d080d 100644
--- a/async.c
+++ b/async.c
@@ -230,7 +230,6 @@ aio_ctx_finalize(GSource *source)
event_notifier_cleanup(&ctx->notifier);
rfifolock_destroy(&ctx->lock);
qemu_mutex_destroy(&ctx->bh_lock);
- g_array_free(ctx->pollfds, TRUE);
timerlistgroup_deinit(&ctx->tlg);
}
@@ -302,7 +301,6 @@ AioContext *aio_context_new(Error **errp)
aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *)
event_notifier_test_and_clear);
- ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
ctx->thread_pool = NULL;
qemu_mutex_init(&ctx->bh_lock);
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
diff --git a/include/block/aio.h b/include/block/aio.h
index 7d1e26b..0dc7a25 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -82,9 +82,6 @@ struct AioContext {
/* Used for aio_notify. */
EventNotifier notifier;
- /* GPollFDs for aio_poll() */
- GArray *pollfds;
-
/* Thread pool for performing work and receiving completion callbacks */
struct ThreadPool *thread_pool;
--
1.8.3.1
- [Qemu-devel] [PULL 01/76] savevm: create snapshot failed when id_str already exists, (continued)
- [Qemu-devel] [PULL 01/76] savevm: create snapshot failed when id_str already exists, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 04/76] hw/arm/nseries: convert ffs(3) to ctz32(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 05/76] uninorth: convert ffs(3) to ctz32(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 08/76] sd: convert sd_normal_command() ffs(3) call to ctz32(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 06/76] Convert (ffs(val) - 1) to ctz32(val), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 07/76] Convert ffs() != 0 callers to ctz32(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 09/76] omap_intc: convert ffs(3) to ctz32() in omap_inth_sir_update(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 11/76] checkpatch: complain about ffs(3) calls, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 12/76] block: Switch to host monotonic clock for IO throttling, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 10/76] os-win32: drop ffs(3) prototype, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 13/76] aio-posix: move pollfds to thread-local storage,
Kevin Wolf <=
- [Qemu-devel] [PULL 14/76] AioContext: acquire/release AioContext during aio_poll, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 16/76] block-backend: Expose bdrv_write_zeroes(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 15/76] iothread: release iothread around aio_poll, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 18/76] qemu-iotests: Some qemu-img convert tests, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 17/76] qemu-img convert: Rewrite copying logic, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 19/76] blkdebug: Add bdrv_truncate(), Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 22/76] scripts: add 'qemu coroutine' command to qemu-gdb.py, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 20/76] vhdx: Fix zero-fill iov length, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 25/76] MAINTAINERS: Add Fam Zheng as Null block driver maintainer, Kevin Wolf, 2015/04/28
- [Qemu-devel] [PULL 21/76] thread-pool: clean up thread_pool_completion_bh(), Kevin Wolf, 2015/04/28