Commit f3926945 authored by Fam Zheng's avatar Fam Zheng Committed by Paolo Bonzini
Browse files

iohandler: Use aio API



iohandler.c shares the same interface with aio, but with duplicated
code. It's better to rebase iohandler, also because that aio is a
more friendly interface to multi-threads.

Create a global AioContext instance and let its GSource handle the
iohandler events.

Signed-off-by: default avatarFam Zheng <famz@redhat.com>
Message-Id: <1441596538-4412-1-git-send-email-famz@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 46036b24
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ void qemu_set_fd_handler(int fd,
                         IOHandler *fd_write,
                         void *opaque);

GSource *iohandler_get_g_source(void);
#ifdef CONFIG_POSIX
/**
 * qemu_add_child_watch: Register a child process for reaping.
@@ -265,8 +266,6 @@ void qemu_mutex_unlock_iothread(void);
/* internal interfaces */

void qemu_fd_register(int fd);
void qemu_iohandler_fill(GArray *pollfds);
void qemu_iohandler_poll(GArray *pollfds, int rc);

QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
+15 −96
Original line number Diff line number Diff line
@@ -32,111 +32,30 @@
#include <sys/wait.h>
#endif

typedef struct IOHandlerRecord {
    IOHandler *fd_read;
    IOHandler *fd_write;
    void *opaque;
    QLIST_ENTRY(IOHandlerRecord) next;
    int fd;
    int pollfds_idx;
    bool deleted;
} IOHandlerRecord;

static QLIST_HEAD(, IOHandlerRecord) io_handlers =
    QLIST_HEAD_INITIALIZER(io_handlers);
/* This context runs on top of main loop. We can't reuse qemu_aio_context
 * because iohandlers mustn't be polled by aio_poll(qemu_aio_context). */
static AioContext *iohandler_ctx;

void qemu_set_fd_handler(int fd,
                         IOHandler *fd_read,
                         IOHandler *fd_write,
                         void *opaque)
static void iohandler_init(void)
{
    IOHandlerRecord *ioh;

    assert(fd >= 0);

    if (!fd_read && !fd_write) {
        QLIST_FOREACH(ioh, &io_handlers, next) {
            if (ioh->fd == fd) {
                ioh->deleted = 1;
                break;
            }
        }
    } else {
        QLIST_FOREACH(ioh, &io_handlers, next) {
            if (ioh->fd == fd)
                goto found;
        }
        ioh = g_malloc0(sizeof(IOHandlerRecord));
        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
    found:
        ioh->fd = fd;
        ioh->fd_read = fd_read;
        ioh->fd_write = fd_write;
        ioh->opaque = opaque;
        ioh->pollfds_idx = -1;
        ioh->deleted = 0;
        qemu_notify_event();
    if (!iohandler_ctx) {
        iohandler_ctx = aio_context_new(&error_abort);
    }
}

void qemu_iohandler_fill(GArray *pollfds)
GSource *iohandler_get_g_source(void)
{
    IOHandlerRecord *ioh;

    QLIST_FOREACH(ioh, &io_handlers, next) {
        int events = 0;

        if (ioh->deleted)
            continue;
        if (ioh->fd_read) {
            events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
        }
        if (ioh->fd_write) {
            events |= G_IO_OUT | G_IO_ERR;
        }
        if (events) {
            GPollFD pfd = {
                .fd = ioh->fd,
                .events = events,
            };
            ioh->pollfds_idx = pollfds->len;
            g_array_append_val(pollfds, pfd);
        } else {
            ioh->pollfds_idx = -1;
        }
    }
    iohandler_init();
    return aio_get_g_source(iohandler_ctx);
}

void qemu_iohandler_poll(GArray *pollfds, int ret)
void qemu_set_fd_handler(int fd,
                         IOHandler *fd_read,
                         IOHandler *fd_write,
                         void *opaque)
{
    if (ret > 0) {
        IOHandlerRecord *pioh, *ioh;

        QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
            int revents = 0;

            if (!ioh->deleted && ioh->pollfds_idx != -1) {
                GPollFD *pfd = &g_array_index(pollfds, GPollFD,
                                              ioh->pollfds_idx);
                revents = pfd->revents;
            }

            if (!ioh->deleted && ioh->fd_read &&
                (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
                ioh->fd_read(ioh->opaque);
            }
            if (!ioh->deleted && ioh->fd_write &&
                (revents & (G_IO_OUT | G_IO_ERR))) {
                ioh->fd_write(ioh->opaque);
            }

            /* Do this last in case read/write handlers marked it for deletion */
            if (ioh->deleted) {
                QLIST_REMOVE(ioh, next);
                g_free(ioh);
            }
        }
    }
    iohandler_init();
    aio_set_fd_handler(iohandler_ctx, fd, fd_read, fd_write, opaque);
}

/* reaping of zombies.  right now we're not passing the status to
+3 −2
Original line number Diff line number Diff line
@@ -161,6 +161,9 @@ int qemu_init_main_loop(Error **errp)
    src = aio_get_g_source(qemu_aio_context);
    g_source_attach(src, NULL);
    g_source_unref(src);
    src = iohandler_get_g_source();
    g_source_attach(src, NULL);
    g_source_unref(src);
    return 0;
}

@@ -487,7 +490,6 @@ int main_loop_wait(int nonblocking)
#ifdef CONFIG_SLIRP
    slirp_pollfds_fill(gpollfds, &timeout);
#endif
    qemu_iohandler_fill(gpollfds);

    if (timeout == UINT32_MAX) {
        timeout_ns = -1;
@@ -500,7 +502,6 @@ int main_loop_wait(int nonblocking)
                                          &main_loop_tlg));

    ret = os_host_main_loop_wait(timeout_ns);
    qemu_iohandler_poll(gpollfds, ret);
#ifdef CONFIG_SLIRP
    slirp_pollfds_poll(gpollfds, (ret < 0));
#endif