Commit 6cf38cbf 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 Tue 27 Mar 2018 15:41:11 BST
# gpg:                using RSA key 9CA4ABB381AB73C8
# 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:
  MAINTAINERS: add include/block/aio-wait.h
  coroutine: add test-aio coroutine queue chaining test case
  coroutine: avoid co_queue_wakeup recursion
  queue: add QSIMPLEQ_PREPEND()

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents dfe732fb f5a53faa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1351,6 +1351,7 @@ F: util/aio-*.c
F: block/io.c
F: migration/block*
F: include/block/aio.h
F: include/block/aio-wait.h
F: scripts/qemugdb/aio.py
T: git git://github.com/stefanha/qemu.git block

+1 −2
Original line number Diff line number Diff line
@@ -249,8 +249,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
    BdrvCoDrainData data;

    /* Calling bdrv_drain() from a BH ensures the current coroutine yields and
     * other coroutines run if they were queued from
     * qemu_co_queue_run_restart(). */
     * other coroutines run if they were queued by aio_co_enter(). */

    assert(qemu_in_coroutine());
    data = (BdrvCoDrainData) {
+0 −1
Original line number Diff line number Diff line
@@ -68,6 +68,5 @@ Coroutine *qemu_coroutine_new(void);
void qemu_coroutine_delete(Coroutine *co);
CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to,
                                      CoroutineAction action);
void coroutine_fn qemu_co_queue_run_restart(Coroutine *co);

#endif
+8 −0
Original line number Diff line number Diff line
@@ -324,6 +324,14 @@ struct { \
    }                                                                   \
} while (/*CONSTCOND*/0)

#define QSIMPLEQ_PREPEND(head1, head2) do {                             \
    if (!QSIMPLEQ_EMPTY((head2))) {                                     \
        *(head2)->sqh_last = (head1)->sqh_first;                        \
        (head1)->sqh_first = (head2)->sqh_first;                          \
        QSIMPLEQ_INIT((head2));                                         \
    }                                                                   \
} while (/*CONSTCOND*/0)

#define QSIMPLEQ_LAST(head, type, field)                                \
    (QSIMPLEQ_EMPTY((head)) ?                                           \
        NULL :                                                          \
+51 −12
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
#include "qemu/timer.h"
#include "qemu/sockets.h"
#include "qemu/error-report.h"
#include "qemu/coroutine.h"
#include "qemu/main-loop.h"

static AioContext *ctx;

@@ -827,24 +829,59 @@ static void test_source_timer_schedule(void)
    timer_del(&data.timer);
}

/*
 * Check that aio_co_enter() can chain many times
 *
 * Two coroutines should be able to invoke each other via aio_co_enter() many
 * times without hitting a limit like stack exhaustion.  In other words, the
 * calls should be chained instead of nested.
 */

/* End of tests.  */
typedef struct {
    Coroutine *other;
    unsigned i;
    unsigned max;
} ChainData;

int main(int argc, char **argv)
static void coroutine_fn chain(void *opaque)
{
    Error *local_error = NULL;
    GSource *src;
    ChainData *data = opaque;

    init_clocks(NULL);
    for (data->i = 0; data->i < data->max; data->i++) {
        /* Queue up the other coroutine... */
        aio_co_enter(ctx, data->other);

    ctx = aio_context_new(&local_error);
    if (!ctx) {
        error_reportf_err(local_error, "Failed to create AIO Context: ");
        exit(1);
        /* ...and give control to it */
        qemu_coroutine_yield();
    }
    src = aio_get_g_source(ctx);
    g_source_attach(src, NULL);
    g_source_unref(src);
}

static void test_queue_chaining(void)
{
    /* This number of iterations hit stack exhaustion in the past: */
    ChainData data_a = { .max = 25000 };
    ChainData data_b = { .max = 25000 };

    data_b.other = qemu_coroutine_create(chain, &data_a);
    data_a.other = qemu_coroutine_create(chain, &data_b);

    qemu_coroutine_enter(data_b.other);

    g_assert_cmpint(data_a.i, ==, data_a.max);
    g_assert_cmpint(data_b.i, ==, data_b.max - 1);

    /* Allow the second coroutine to terminate */
    qemu_coroutine_enter(data_a.other);

    g_assert_cmpint(data_b.i, ==, data_b.max);
}

/* End of tests.  */

int main(int argc, char **argv)
{
    qemu_init_main_loop(&error_fatal);
    ctx = qemu_get_aio_context();

    while (g_main_context_iteration(NULL, false));

@@ -864,6 +901,8 @@ int main(int argc, char **argv)
    g_test_add_func("/aio/external-client",         test_aio_external_client);
    g_test_add_func("/aio/timer/schedule",          test_timer_schedule);

    g_test_add_func("/aio/coroutine/queue-chaining", test_queue_chaining);

    g_test_add_func("/aio-gsource/flush",                   test_source_flush);
    g_test_add_func("/aio-gsource/bh/schedule",             test_source_bh_schedule);
    g_test_add_func("/aio-gsource/bh/schedule10",           test_source_bh_schedule10);
Loading