aio: add I/O handlers to the AioContext interface
With this patch, I/O handlers (including event notifier handlers) can be attached to a single AioContext. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
f627aab1cc
commit
a915f4bc97
52
aio.c
52
aio.c
@ -18,15 +18,6 @@
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
/* The list of registered AIO handlers */
|
||||
static QLIST_HEAD(, AioHandler) aio_handlers;
|
||||
|
||||
/* This is a simple lock used to protect the aio_handlers list. Specifically,
|
||||
* it's used to ensure that no callbacks are removed while we're walking and
|
||||
* dispatching callbacks.
|
||||
*/
|
||||
static int walking_handlers;
|
||||
|
||||
struct AioHandler
|
||||
{
|
||||
int fd;
|
||||
@ -38,11 +29,11 @@ struct AioHandler
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
|
||||
static AioHandler *find_aio_handler(int fd)
|
||||
static AioHandler *find_aio_handler(AioContext *ctx, int fd)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (node->fd == fd)
|
||||
if (!node->deleted)
|
||||
return node;
|
||||
@ -51,7 +42,8 @@ static AioHandler *find_aio_handler(int fd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qemu_aio_set_fd_handler(int fd,
|
||||
void aio_set_fd_handler(AioContext *ctx,
|
||||
int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
@ -59,13 +51,13 @@ void qemu_aio_set_fd_handler(int fd,
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
node = find_aio_handler(fd);
|
||||
node = find_aio_handler(ctx, fd);
|
||||
|
||||
/* Are we deleting the fd handler? */
|
||||
if (!io_read && !io_write) {
|
||||
if (node) {
|
||||
/* If the lock is held, just mark the node as deleted */
|
||||
if (walking_handlers)
|
||||
if (ctx->walking_handlers)
|
||||
node->deleted = 1;
|
||||
else {
|
||||
/* Otherwise, delete it for real. We can't just mark it as
|
||||
@ -81,7 +73,7 @@ void qemu_aio_set_fd_handler(int fd,
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node->fd = fd;
|
||||
QLIST_INSERT_HEAD(&aio_handlers, node, node);
|
||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||
}
|
||||
/* Update handler with latest information */
|
||||
node->io_read = io_read;
|
||||
@ -89,25 +81,19 @@ void qemu_aio_set_fd_handler(int fd,
|
||||
node->io_flush = io_flush;
|
||||
node->opaque = opaque;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
|
||||
}
|
||||
|
||||
void qemu_aio_set_event_notifier(EventNotifier *notifier,
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
EventNotifierHandler *io_read,
|
||||
AioFlushEventNotifierHandler *io_flush)
|
||||
{
|
||||
qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
|
||||
(IOHandler *)io_read, NULL,
|
||||
(AioFlushHandler *)io_flush, notifier);
|
||||
}
|
||||
|
||||
void qemu_aio_flush(void)
|
||||
{
|
||||
while (qemu_aio_wait());
|
||||
}
|
||||
|
||||
bool qemu_aio_wait(void)
|
||||
bool aio_wait(AioContext *ctx)
|
||||
{
|
||||
AioHandler *node;
|
||||
fd_set rdfds, wrfds;
|
||||
@ -120,18 +106,18 @@ bool qemu_aio_wait(void)
|
||||
* Do not call select in this case, because it is possible that the caller
|
||||
* does not need a complete flush (as is the case for qemu_aio_wait loops).
|
||||
*/
|
||||
if (qemu_bh_poll()) {
|
||||
if (aio_bh_poll(ctx)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
walking_handlers++;
|
||||
ctx->walking_handlers++;
|
||||
|
||||
FD_ZERO(&rdfds);
|
||||
FD_ZERO(&wrfds);
|
||||
|
||||
/* fill fd sets */
|
||||
busy = false;
|
||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
/* If there aren't pending AIO operations, don't invoke callbacks.
|
||||
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
||||
* wait indefinitely.
|
||||
@ -152,7 +138,7 @@ bool qemu_aio_wait(void)
|
||||
}
|
||||
}
|
||||
|
||||
walking_handlers--;
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* No AIO operations? Get us out of here */
|
||||
if (!busy) {
|
||||
@ -166,11 +152,11 @@ bool qemu_aio_wait(void)
|
||||
if (ret > 0) {
|
||||
/* we have to walk very carefully in case
|
||||
* qemu_aio_set_fd_handler is called while we're walking */
|
||||
node = QLIST_FIRST(&aio_handlers);
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
|
||||
walking_handlers++;
|
||||
ctx->walking_handlers++;
|
||||
|
||||
if (!node->deleted &&
|
||||
FD_ISSET(node->fd, &rdfds) &&
|
||||
@ -186,9 +172,9 @@ bool qemu_aio_wait(void)
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
walking_handlers--;
|
||||
ctx->walking_handlers--;
|
||||
|
||||
if (!walking_handlers && tmp->deleted) {
|
||||
if (!ctx->walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
6
async.c
6
async.c
@ -136,7 +136,13 @@ void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AioContext *aio_context_new(void)
|
||||
{
|
||||
return g_new0(AioContext, 1);
|
||||
}
|
||||
|
||||
void aio_flush(AioContext *ctx)
|
||||
{
|
||||
while (aio_wait(ctx));
|
||||
}
|
||||
|
33
main-loop.c
33
main-loop.c
@ -526,3 +526,36 @@ int qemu_bh_poll(void)
|
||||
{
|
||||
return aio_bh_poll(qemu_aio_context);
|
||||
}
|
||||
|
||||
void qemu_aio_flush(void)
|
||||
{
|
||||
aio_flush(qemu_aio_context);
|
||||
}
|
||||
|
||||
bool qemu_aio_wait(void)
|
||||
{
|
||||
return aio_wait(qemu_aio_context);
|
||||
}
|
||||
|
||||
void qemu_aio_set_fd_handler(int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
void *opaque)
|
||||
{
|
||||
aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,
|
||||
opaque);
|
||||
|
||||
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
void qemu_aio_set_event_notifier(EventNotifier *notifier,
|
||||
EventNotifierHandler *io_read,
|
||||
AioFlushEventNotifierHandler *io_flush)
|
||||
{
|
||||
qemu_aio_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
(IOHandler *)io_read, NULL,
|
||||
(AioFlushHandler *)io_flush, notifier);
|
||||
}
|
||||
#endif
|
||||
|
34
qemu-aio.h
34
qemu-aio.h
@ -15,6 +15,7 @@
|
||||
#define QEMU_AIO_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "event_notifier.h"
|
||||
|
||||
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
|
||||
@ -43,6 +44,15 @@ typedef void QEMUBHFunc(void *opaque);
|
||||
typedef void IOHandler(void *opaque);
|
||||
|
||||
typedef struct AioContext {
|
||||
/* The list of registered AIO handlers */
|
||||
QLIST_HEAD(, AioHandler) aio_handlers;
|
||||
|
||||
/* This is a simple lock used to protect the aio_handlers list.
|
||||
* Specifically, it's used to ensure that no callbacks are removed while
|
||||
* we're walking and dispatching callbacks.
|
||||
*/
|
||||
int walking_handlers;
|
||||
|
||||
/* Anchor of the list of Bottom Halves belonging to the context */
|
||||
struct QEMUBH *first_bh;
|
||||
|
||||
@ -121,7 +131,7 @@ void qemu_bh_delete(QEMUBH *bh);
|
||||
|
||||
/* Flush any pending AIO operation. This function will block until all
|
||||
* outstanding AIO operations have been completed or cancelled. */
|
||||
void qemu_aio_flush(void);
|
||||
void aio_flush(AioContext *ctx);
|
||||
|
||||
/* Wait for a single AIO completion to occur. This function will wait
|
||||
* until a single AIO event has completed and it will ensure something
|
||||
@ -129,7 +139,7 @@ void qemu_aio_flush(void);
|
||||
* result of executing I/O completion or bh callbacks.
|
||||
*
|
||||
* Return whether there is still any pending AIO operation. */
|
||||
bool qemu_aio_wait(void);
|
||||
bool aio_wait(AioContext *ctx);
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
|
||||
@ -142,7 +152,8 @@ typedef int (AioFlushHandler)(void *opaque);
|
||||
* Code that invokes AIO completion functions should rely on this function
|
||||
* instead of qemu_set_fd_handler[2].
|
||||
*/
|
||||
void qemu_aio_set_fd_handler(int fd,
|
||||
void aio_set_fd_handler(AioContext *ctx,
|
||||
int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
@ -156,8 +167,25 @@ void qemu_aio_set_fd_handler(int fd,
|
||||
* Code that invokes AIO completion functions should rely on this function
|
||||
* instead of event_notifier_set_handler.
|
||||
*/
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
EventNotifierHandler *io_read,
|
||||
AioFlushEventNotifierHandler *io_flush);
|
||||
|
||||
/* Functions to operate on the main QEMU AioContext. */
|
||||
|
||||
void qemu_aio_flush(void);
|
||||
bool qemu_aio_wait(void);
|
||||
void qemu_aio_set_event_notifier(EventNotifier *notifier,
|
||||
EventNotifierHandler *io_read,
|
||||
AioFlushEventNotifierHandler *io_flush);
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
void qemu_aio_set_fd_handler(int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
void *opaque);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user