aio: convert aio_poll() to g_poll(3)

AioHandler already has a GPollFD so we can directly use its
events/revents.

Add the int pollfds_idx field to AioContext so we can map g_poll(3)
results back to AioHandlers.

Reuse aio_dispatch() to invoke handlers after g_poll(3).

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Message-id: 1361356113-11049-10-git-send-email-stefanha@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Stefan Hajnoczi 2013-02-20 11:28:32 +01:00 committed by Anthony Liguori
parent d0c8d2c05f
commit 6b5f876252
3 changed files with 29 additions and 43 deletions

View File

@ -25,6 +25,7 @@ struct AioHandler
IOHandler *io_write; IOHandler *io_write;
AioFlushHandler *io_flush; AioFlushHandler *io_flush;
int deleted; int deleted;
int pollfds_idx;
void *opaque; void *opaque;
QLIST_ENTRY(AioHandler) node; QLIST_ENTRY(AioHandler) node;
}; };
@ -85,6 +86,7 @@ void aio_set_fd_handler(AioContext *ctx,
node->io_write = io_write; node->io_write = io_write;
node->io_flush = io_flush; node->io_flush = io_flush;
node->opaque = opaque; node->opaque = opaque;
node->pollfds_idx = -1;
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0); node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
node->pfd.events |= (io_write ? G_IO_OUT : 0); node->pfd.events |= (io_write ? G_IO_OUT : 0);
@ -177,10 +179,7 @@ static bool aio_dispatch(AioContext *ctx)
bool aio_poll(AioContext *ctx, bool blocking) bool aio_poll(AioContext *ctx, bool blocking)
{ {
static struct timeval tv0;
AioHandler *node; AioHandler *node;
fd_set rdfds, wrfds;
int max_fd = -1;
int ret; int ret;
bool busy, progress; bool busy, progress;
@ -206,12 +205,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
ctx->walking_handlers++; ctx->walking_handlers++;
FD_ZERO(&rdfds); g_array_set_size(ctx->pollfds, 0);
FD_ZERO(&wrfds);
/* fill fd sets */ /* fill pollfds */
busy = false; busy = false;
QLIST_FOREACH(node, &ctx->aio_handlers, node) { QLIST_FOREACH(node, &ctx->aio_handlers, node) {
node->pollfds_idx = -1;
/* If there aren't pending AIO operations, don't invoke callbacks. /* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would * Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely. * wait indefinitely.
@ -222,13 +222,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
} }
busy = true; busy = true;
} }
if (!node->deleted && node->io_read) { if (!node->deleted && node->pfd.events) {
FD_SET(node->pfd.fd, &rdfds); GPollFD pfd = {
max_fd = MAX(max_fd, node->pfd.fd + 1); .fd = node->pfd.fd,
} .events = node->pfd.events,
if (!node->deleted && node->io_write) { };
FD_SET(node->pfd.fd, &wrfds); node->pollfds_idx = ctx->pollfds->len;
max_fd = MAX(max_fd, node->pfd.fd + 1); g_array_append_val(ctx->pollfds, pfd);
} }
} }
@ -240,41 +240,22 @@ bool aio_poll(AioContext *ctx, bool blocking)
} }
/* wait until next event */ /* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0); ret = g_poll((GPollFD *)ctx->pollfds->data,
ctx->pollfds->len,
blocking ? -1 : 0);
/* if we have any readable fds, dispatch event */ /* if we have any readable fds, dispatch event */
if (ret > 0) { if (ret > 0) {
/* we have to walk very carefully in case QLIST_FOREACH(node, &ctx->aio_handlers, node) {
* qemu_aio_set_fd_handler is called while we're walking */ if (node->pollfds_idx != -1) {
node = QLIST_FIRST(&ctx->aio_handlers); GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
while (node) { node->pollfds_idx);
AioHandler *tmp; node->pfd.revents = pfd->revents;
}
ctx->walking_handlers++; }
if (aio_dispatch(ctx)) {
if (!node->deleted &&
FD_ISSET(node->pfd.fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
progress = true; progress = true;
} }
if (!node->deleted &&
FD_ISSET(node->pfd.fd, &wrfds) &&
node->io_write) {
node->io_write(node->opaque);
progress = true;
}
tmp = node;
node = QLIST_NEXT(node, node);
ctx->walking_handlers--;
if (!ctx->walking_handlers && tmp->deleted) {
QLIST_REMOVE(tmp, node);
g_free(tmp);
}
}
} }
assert(progress || busy); assert(progress || busy);

View File

@ -174,6 +174,7 @@ aio_ctx_finalize(GSource *source)
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL); aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
event_notifier_cleanup(&ctx->notifier); event_notifier_cleanup(&ctx->notifier);
g_array_free(ctx->pollfds, TRUE);
} }
static GSourceFuncs aio_source_funcs = { static GSourceFuncs aio_source_funcs = {
@ -198,6 +199,7 @@ AioContext *aio_context_new(void)
{ {
AioContext *ctx; AioContext *ctx;
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext)); ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
event_notifier_init(&ctx->notifier, false); event_notifier_init(&ctx->notifier, false);
aio_set_event_notifier(ctx, &ctx->notifier, aio_set_event_notifier(ctx, &ctx->notifier,
(EventNotifierHandler *) (EventNotifierHandler *)

View File

@ -63,6 +63,9 @@ typedef struct AioContext {
/* Used for aio_notify. */ /* Used for aio_notify. */
EventNotifier notifier; EventNotifier notifier;
/* GPollFDs for aio_poll() */
GArray *pollfds;
} AioContext; } AioContext;
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */