Commit e92fbc75 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging



# gpg: Signature made Wed 04 Jan 2017 13:29:09 GMT
# gpg:                using RSA key 0x9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35  775A 9CA4 ABB3 81AB 73C8

* remotes/stefanha/tags/block-pull-request:
  iothread: add poll-grow and poll-shrink parameters
  aio: self-tune polling time
  virtio: disable virtqueue notifications during polling
  aio: add .io_poll_begin/end() callbacks
  virtio: turn vq->notification into a nested counter
  virtio-scsi: suppress virtqueue kick during processing
  virtio-blk: suppress virtqueue kick during processing
  iothread: add polling parameters
  linux-aio: poll ring for completions
  virtio: poll virtqueues for new buffers
  aio: add polling mode to AioContext
  aio: add AioPollFn and io_poll() interface
  aio: add flag to skip fds to aio_dispatch()
  HACKING: document #include order

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 9c904a75 5e5db499
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
1. Preprocessor

1.1. Variadic macros

For variadic macros, stick with this C99-like syntax:

#define DPRINTF(fmt, ...)                                       \
    do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)

1.2. Include directives

Order include directives as follows:

#include "qemu/osdep.h"  /* Always first... */
#include <...>           /* then system headers... */
#include "..."           /* and finally QEMU headers. */

The "qemu/osdep.h" header contains preprocessor macros that affect the behavior
of core system headers like <stdint.h>.  It must be the first include so that
core system headers included by external libraries get the preprocessor macros
that QEMU depends on.

Do not include "qemu/osdep.h" from header files since the .c file will have
already included it.

2. C types

It should be common sense to use the right type, but we have collected
+275 −33
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include "block/block.h"
#include "qemu/queue.h"
#include "qemu/sockets.h"
#include "qemu/cutils.h"
#include "trace.h"
#ifdef CONFIG_EPOLL_CREATE1
#include <sys/epoll.h>
#endif
@@ -27,6 +29,9 @@ struct AioHandler
    GPollFD pfd;
    IOHandler *io_read;
    IOHandler *io_write;
    AioPollFn *io_poll;
    IOHandler *io_poll_begin;
    IOHandler *io_poll_end;
    int deleted;
    void *opaque;
    bool is_external;
@@ -200,6 +205,7 @@ void aio_set_fd_handler(AioContext *ctx,
                        bool is_external,
                        IOHandler *io_read,
                        IOHandler *io_write,
                        AioPollFn *io_poll,
                        void *opaque)
{
    AioHandler *node;
@@ -209,7 +215,7 @@ void aio_set_fd_handler(AioContext *ctx,
    node = find_aio_handler(ctx, fd);

    /* Are we deleting the fd handler? */
    if (!io_read && !io_write) {
    if (!io_read && !io_write && !io_poll) {
        if (node == NULL) {
            return;
        }
@@ -228,6 +234,10 @@ void aio_set_fd_handler(AioContext *ctx,
            QLIST_REMOVE(node, node);
            deleted = true;
        }

        if (!node->io_poll) {
            ctx->poll_disable_cnt--;
        }
    } else {
        if (node == NULL) {
            /* Alloc and insert if it's not already there */
@@ -237,10 +247,16 @@ void aio_set_fd_handler(AioContext *ctx,

            g_source_add_poll(&ctx->source, &node->pfd);
            is_new = true;

            ctx->poll_disable_cnt += !io_poll;
        } else {
            ctx->poll_disable_cnt += !io_poll - !node->io_poll;
        }

        /* Update handler with latest information */
        node->io_read = io_read;
        node->io_write = io_write;
        node->io_poll = io_poll;
        node->opaque = opaque;
        node->is_external = is_external;

@@ -250,22 +266,83 @@ void aio_set_fd_handler(AioContext *ctx,

    aio_epoll_update(ctx, node, is_new);
    aio_notify(ctx);

    if (deleted) {
        g_free(node);
    }
}

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,
                            EventNotifierHandler *io_read)
                            EventNotifierHandler *io_read,
                            AioPollFn *io_poll)
{
    aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
                       is_external, (IOHandler *)io_read, NULL, notifier);
    aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external,
                       (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;
}

@@ -290,9 +367,13 @@ bool aio_pending(AioContext *ctx)
    return false;
}

bool aio_dispatch(AioContext *ctx)
/*
 * Note that dispatch_fds == false has the side-effect of post-poning the
 * freeing of deleted handlers.
 */
bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
{
    AioHandler *node;
    AioHandler *node = NULL;
    bool progress = false;

    /*
@@ -308,7 +389,9 @@ bool aio_dispatch(AioContext *ctx)
     * We have to walk very carefully in case aio_set_fd_handler is
     * called while we're walking.
     */
    if (dispatch_fds) {
        node = QLIST_FIRST(&ctx->aio_handlers);
    }
    while (node) {
        AioHandler *tmp;
        int revents;
@@ -400,12 +483,100 @@ 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
 *
 * Polls for a given time.
 *
 * Note that ctx->notify_me must be non-zero so this function can detect
 * aio_notify().
 *
 * Note that the caller must have incremented ctx->walking_handlers.
 *
 * Returns: true if progress was made, false otherwise
 */
static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
{
    bool progress;
    int64_t end_time;

    assert(ctx->notify_me);
    assert(ctx->walking_handlers > 0);
    assert(ctx->poll_disable_cnt == 0);

    trace_run_poll_handlers_begin(ctx, max_ns);

    end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns;

    do {
        progress = run_poll_handlers_once(ctx);
    } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);

    trace_run_poll_handlers_end(ctx, progress);

    return progress;
}

/* try_poll_mode:
 * @ctx: the AioContext
 * @blocking: busy polling is only attempted when blocking is true
 *
 * ctx->notify_me must be non-zero so this function can detect aio_notify().
 *
 * Note that the caller must have incremented ctx->walking_handlers.
 *
 * Returns: true if progress was made, false otherwise
 */
static bool try_poll_mode(AioContext *ctx, bool blocking)
{
    if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) {
        /* See qemu_soonest_timeout() uint64_t hack */
        int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
                             (uint64_t)ctx->poll_ns);

        if (max_ns) {
            poll_set_started(ctx, true);

            if (run_poll_handlers(ctx, max_ns)) {
                return true;
            }
        }
    }

    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)
{
    AioHandler *node;
    int i, ret;
    int i;
    int ret = 0;
    bool progress;
    int64_t timeout;
    int64_t start = 0;

    aio_context_acquire(ctx);
    progress = false;
@@ -423,6 +594,13 @@ bool aio_poll(AioContext *ctx, bool blocking)

    ctx->walking_handlers++;

    if (ctx->poll_max_ns) {
        start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
    }

    if (try_poll_mode(ctx, blocking)) {
        progress = true;
    } else {
        assert(npfd == 0);

        /* fill pollfds */
@@ -453,11 +631,54 @@ bool aio_poll(AioContext *ctx, bool blocking)
        } else  {
            ret = qemu_poll_ns(pollfds, npfd, timeout);
        }
        if (timeout) {
            aio_context_acquire(ctx);
        }
    }

    if (blocking) {
        atomic_sub(&ctx->notify_me, 2);
    }
    if (timeout) {
        aio_context_acquire(ctx);

    /* Adjust polling time */
    if (ctx->poll_max_ns) {
        int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start;

        if (block_ns <= ctx->poll_ns) {
            /* This is the sweet spot, no adjustment needed */
        } else if (block_ns > ctx->poll_max_ns) {
            /* We'd have to poll for too long, poll less */
            int64_t old = ctx->poll_ns;

            if (ctx->poll_shrink) {
                ctx->poll_ns /= ctx->poll_shrink;
            } else {
                ctx->poll_ns = 0;
            }

            trace_poll_shrink(ctx, old, ctx->poll_ns);
        } else if (ctx->poll_ns < ctx->poll_max_ns &&
                   block_ns < ctx->poll_max_ns) {
            /* There is room to grow, poll longer */
            int64_t old = ctx->poll_ns;
            int64_t grow = ctx->poll_grow;

            if (grow == 0) {
                grow = 2;
            }

            if (ctx->poll_ns) {
                ctx->poll_ns *= grow;
            } else {
                ctx->poll_ns = 4000; /* start polling at 4 microseconds */
            }

            if (ctx->poll_ns > ctx->poll_max_ns) {
                ctx->poll_ns = ctx->poll_max_ns;
            }

            trace_poll_grow(ctx, old, ctx->poll_ns);
        }
    }

    aio_notify_accept(ctx);
@@ -473,7 +694,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
    ctx->walking_handlers--;

    /* Run dispatch even if there were no readable fds to run timers */
    if (aio_dispatch(ctx)) {
    if (aio_dispatch(ctx, ret > 0)) {
        progress = true;
    }

@@ -484,6 +705,13 @@ bool aio_poll(AioContext *ctx, bool blocking)

void aio_context_setup(AioContext *ctx)
{
    /* TODO remove this in final patch submission */
    if (getenv("QEMU_AIO_POLL_MAX_NS")) {
        fprintf(stderr, "The QEMU_AIO_POLL_MAX_NS environment variable has "
                "been replaced with -object iothread,poll-max-ns=NUM\n");
        exit(1);
    }

#ifdef CONFIG_EPOLL_CREATE1
    assert(!ctx->epollfd);
    ctx->epollfd = epoll_create1(EPOLL_CLOEXEC);
@@ -495,3 +723,17 @@ void aio_context_setup(AioContext *ctx)
    }
#endif
}

void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
                                 int64_t grow, int64_t shrink, Error **errp)
{
    /* No thread synchronization here, it doesn't matter if an incorrect value
     * is used once.
     */
    ctx->poll_max_ns = max_ns;
    ctx->poll_ns = 0;
    ctx->poll_grow = grow;
    ctx->poll_shrink = shrink;

    aio_notify(ctx);
}
+29 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "block/block.h"
#include "qemu/queue.h"
#include "qemu/sockets.h"
#include "qapi/error.h"

struct AioHandler {
    EventNotifier *e;
@@ -38,6 +39,7 @@ void aio_set_fd_handler(AioContext *ctx,
                        bool is_external,
                        IOHandler *io_read,
                        IOHandler *io_write,
                        AioPollFn *io_poll,
                        void *opaque)
{
    /* fd is a SOCKET in our case */
@@ -100,10 +102,18 @@ 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,
                            EventNotifierHandler *io_notify)
                            EventNotifierHandler *io_notify,
                            AioPollFn *io_poll)
{
    AioHandler *node;

@@ -150,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;
@@ -271,12 +289,14 @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
    return progress;
}

bool aio_dispatch(AioContext *ctx)
bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
{
    bool progress;

    progress = aio_bh_poll(ctx);
    if (dispatch_fds) {
        progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
    }
    progress |= timerlistgroup_run_timers(&ctx->tlg);
    return progress;
}
@@ -374,3 +394,9 @@ bool aio_poll(AioContext *ctx, bool blocking)
void aio_context_setup(AioContext *ctx)
{
}

void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
                                 int64_t grow, int64_t shrink, Error **errp)
{
    error_setg(errp, "AioContext polling is not implemented on Windows");
}
+18 −3
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ aio_ctx_dispatch(GSource *source,
    AioContext *ctx = (AioContext *) source;

    assert(callback == NULL);
    aio_dispatch(ctx);
    aio_dispatch(ctx, true);
    return true;
}

@@ -282,7 +282,7 @@ aio_ctx_finalize(GSource *source)
    }
    qemu_mutex_unlock(&ctx->bh_lock);

    aio_set_event_notifier(ctx, &ctx->notifier, false, NULL);
    aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL);
    event_notifier_cleanup(&ctx->notifier);
    qemu_rec_mutex_destroy(&ctx->lock);
    qemu_mutex_destroy(&ctx->bh_lock);
@@ -349,6 +349,15 @@ static void event_notifier_dummy_cb(EventNotifier *e)
{
}

/* Returns true if aio_notify() was called (e.g. a BH was scheduled) */
static bool event_notifier_poll(void *opaque)
{
    EventNotifier *e = opaque;
    AioContext *ctx = container_of(e, AioContext, notifier);

    return atomic_read(&ctx->notified);
}

AioContext *aio_context_new(Error **errp)
{
    int ret;
@@ -366,7 +375,8 @@ AioContext *aio_context_new(Error **errp)
    aio_set_event_notifier(ctx, &ctx->notifier,
                           false,
                           (EventNotifierHandler *)
                           event_notifier_dummy_cb);
                           event_notifier_dummy_cb,
                           event_notifier_poll);
#ifdef CONFIG_LINUX_AIO
    ctx->linux_aio = NULL;
#endif
@@ -375,6 +385,11 @@ AioContext *aio_context_new(Error **errp)
    qemu_rec_mutex_init(&ctx->lock);
    timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);

    ctx->poll_ns = 0;
    ctx->poll_max_ns = 0;
    ctx->poll_grow = 0;
    ctx->poll_shrink = 0;

    return ctx;
fail:
    g_source_destroy(&ctx->source);
+4 −4
Original line number Diff line number Diff line
@@ -192,19 +192,19 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
    switch (action) {
        case CURL_POLL_IN:
            aio_set_fd_handler(s->aio_context, fd, false,
                               curl_multi_read, NULL, state);
                               curl_multi_read, NULL, NULL, state);
            break;
        case CURL_POLL_OUT:
            aio_set_fd_handler(s->aio_context, fd, false,
                               NULL, curl_multi_do, state);
                               NULL, curl_multi_do, NULL, state);
            break;
        case CURL_POLL_INOUT:
            aio_set_fd_handler(s->aio_context, fd, false,
                               curl_multi_read, curl_multi_do, state);
                               curl_multi_read, curl_multi_do, NULL, state);
            break;
        case CURL_POLL_REMOVE:
            aio_set_fd_handler(s->aio_context, fd, false,
                               NULL, NULL, NULL);
                               NULL, NULL, NULL, NULL);
            break;
    }

Loading