Exemple #1
0
static void test_co_queue(void)
{
    Coroutine *c1;
    Coroutine *c2;

    c1 = qemu_coroutine_create(c1_fn);
    c2 = qemu_coroutine_create(c2_fn);

    qemu_coroutine_enter(c1, c2);
    memset(c1, 0xff, sizeof(Coroutine));
    qemu_coroutine_enter(c2, NULL);
}
int simple_bus_fdt_init(char *bus_node_path, FDTMachineInfo *fdti, void *unused)
{
    int i;
    int num_children = qemu_devtree_get_num_children(fdti->fdt, bus_node_path,
                                                        1);
    char **children = qemu_devtree_get_children(fdti->fdt, bus_node_path, 1);
    int initialRoutinesPending = fdti->routinesPending;

    DB_PRINT("num child devices: %d\n", num_children);

    for (i = 0; i < num_children; i++) {
        struct FDTInitNodeArgs *init_args = g_malloc0(sizeof(*init_args));
        init_args->node_path = children[i];
        init_args->fdti = fdti;
        fdti->routinesPending++;
        qemu_coroutine_enter(qemu_coroutine_create(fdt_init_node), init_args);
    }

    if (fdti->routinesPending != initialRoutinesPending) {
        bdrv_drain_all();
    }

    g_free(children);
    return 0;
}
Exemple #3
0
static int do_co_write_zeroes(int64_t offset, int count, int *total)
{
    Coroutine *co;
    CoWriteZeroes data = {
        .offset = offset,
        .count  = count,
        .total  = total,
        .done   = false,
    };

    co = qemu_coroutine_create(co_write_zeroes_entry);
    qemu_coroutine_enter(co, &data);
    while (!data.done) {
        qemu_aio_wait();
    }
    if (data.ret < 0) {
        return data.ret;
    } else {
        return 1;
    }
}

static int do_write_compressed(char *buf, int64_t offset, int count, int *total)
{
    int ret;

    ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9);
    if (ret < 0) {
        return ret;
    }
    *total = count;
    return 1;
}
Exemple #4
0
static void test_self(void)
{
    Coroutine *coroutine;

    coroutine = qemu_coroutine_create(verify_self);
    qemu_coroutine_enter(coroutine, coroutine);
}
Exemple #5
0
static void test_lifecycle(void)
{
    Coroutine *coroutine;
    bool done = false;

    /* Create, enter, and return from coroutine */
    coroutine = qemu_coroutine_create(set_and_exit);
    qemu_coroutine_enter(coroutine, &done);
    g_assert(done); /* expect done to be true (first time) */

    /* Repeat to check that no state affects this test */
    done = false;
    coroutine = qemu_coroutine_create(set_and_exit);
    qemu_coroutine_enter(coroutine, &done);
    g_assert(done); /* expect done to be true (second time) */
}
Exemple #6
0
static void test_nesting(void)
{
    Coroutine *root;
    NestData nd = {
        .n_enter  = 0,
        .n_return = 0,
        .max      = 128,
    };

    root = qemu_coroutine_create(nest);
    qemu_coroutine_enter(root, &nd);

    /* Must enter and return from max nesting level */
    g_assert_cmpint(nd.n_enter, ==, nd.max);
    g_assert_cmpint(nd.n_return, ==, nd.max);
}

/*
 * Check that yield/enter transfer control correctly
 */

static void coroutine_fn yield_5_times(void *opaque)
{
    bool *done = opaque;
    int i;

    for (i = 0; i < 5; i++) {
        qemu_coroutine_yield();
    }
    *done = true;
}
static int do_co_write_zeroes(int64_t offset, int count, int *total)
{
    Coroutine *co;
    CoWriteZeroes data = {
        .offset = offset,
        .count  = count,
        .total  = total,
        .done   = false,
    };

    co = qemu_coroutine_create(co_write_zeroes_entry);
    qemu_coroutine_enter(co, &data);
    while (!data.done) {
        qemu_aio_wait();
    }
    if (data.ret < 0) {
        return data.ret;
    } else {
        return 1;
    }
}

static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
{
    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
    if (*total < 0) {
        return *total;
    }
    return 1;
}
Exemple #8
0
static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
                             const char *replaces,
                             int64_t speed, int64_t granularity,
                             int64_t buf_size,
                             BlockdevOnError on_source_error,
                             BlockdevOnError on_target_error,
                             BlockDriverCompletionFunc *cb,
                             void *opaque, Error **errp,
                             const BlockJobDriver *driver,
                             bool is_none_mode, BlockDriverState *base)
{
    MirrorBlockJob *s;

    if (granularity == 0) {
        /* Choose the default granularity based on the target file's cluster
         * size, clamped between 4k and 64k.  */
        BlockDriverInfo bdi;
        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
            granularity = MAX(4096, bdi.cluster_size);
            granularity = MIN(65536, granularity);
        } else {
            granularity = 65536;
        }
    }

    assert ((granularity & (granularity - 1)) == 0);

    if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
         on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
        !bdrv_iostatus_is_enabled(bs)) {
        error_set(errp, QERR_INVALID_PARAMETER, "on-source-error");
        return;
    }


    s = block_job_create(driver, bs, speed, cb, opaque, errp);
    if (!s) {
        return;
    }

    s->replaces = g_strdup(replaces);
    s->on_source_error = on_source_error;
    s->on_target_error = on_target_error;
    s->target = target;
    s->is_none_mode = is_none_mode;
    s->base = base;
    s->granularity = granularity;
    s->buf_size = MAX(buf_size, granularity);

    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
    if (!s->dirty_bitmap) {
        return;
    }
    bdrv_set_enable_write_cache(s->target, true);
    bdrv_set_on_error(s->target, on_target_error, on_target_error);
    bdrv_iostatus_enable(s->target);
    s->common.co = qemu_coroutine_create(mirror_run);
    trace_mirror_start(bs, s, s->common.co, opaque);
    qemu_coroutine_enter(s->common.co, s);
}
Exemple #9
0
/* Create a block job that completes with a given return code after a given
 * number of event loop iterations.  The return code is stored in the given
 * result pointer.
 *
 * The event loop iterations can either be handled automatically with a 0 delay
 * timer, or they can be stepped manually by entering the coroutine.
 */
static BlockJob *test_block_job_start(unsigned int iterations,
                                      bool use_timer,
                                      int rc, int *result)
{
    BlockDriverState *bs;
    TestBlockJob *s;
    TestBlockJobCBData *data;
    static unsigned counter;
    char job_id[24];

    data = g_new0(TestBlockJobCBData, 1);
    bs = bdrv_new();
    snprintf(job_id, sizeof(job_id), "job%u", counter++);
    s = block_job_create(job_id, &test_block_job_driver, bs, 0,
                         BLOCK_JOB_DEFAULT, test_block_job_cb,
                         data, &error_abort);
    s->iterations = iterations;
    s->use_timer = use_timer;
    s->rc = rc;
    s->result = result;
    s->common.co = qemu_coroutine_create(test_block_job_run, s);
    data->job = s;
    data->result = result;
    qemu_coroutine_enter(s->common.co);
    return &s->common;
}
Exemple #10
0
static void test_entered(void)
{
    Coroutine *coroutine;

    coroutine = qemu_coroutine_create(verify_entered_step_1, NULL);
    g_assert(!qemu_coroutine_entered(coroutine));
    qemu_coroutine_enter(coroutine);
}
Exemple #11
0
static void test_in_coroutine(void)
{
    Coroutine *coroutine;

    g_assert(!qemu_in_coroutine());

    coroutine = qemu_coroutine_create(verify_in_coroutine);
    qemu_coroutine_enter(coroutine, NULL);
}
Exemple #12
0
void process_incoming_migration(QEMUFile *f)
{
    Coroutine *co = qemu_coroutine_create(process_incoming_migration_co);
    int fd = qemu_get_fd(f);

    assert(fd != -1);
    socket_set_nonblock(fd);
    qemu_coroutine_enter(co, f);
}
Exemple #13
0
static void test_no_dangling_access(void)
{
    Coroutine *c1;
    Coroutine *c2;
    Coroutine tmp;

    c2 = qemu_coroutine_create(c2_fn, NULL);
    c1 = qemu_coroutine_create(c1_fn, c2);

    qemu_coroutine_enter(c1);

    /* c1 shouldn't be used any more now; make sure we segfault if it is */
    tmp = *c1;
    memset(c1, 0xff, sizeof(Coroutine));
    qemu_coroutine_enter(c2);

    /* Must restore the coroutine now to avoid corrupted pool */
    *c1 = tmp;
}
Exemple #14
0
static void nbd_read(void *opaque)
{
    NBDClient *client = opaque;

    if (client->recv_coroutine) {
        qemu_coroutine_enter(client->recv_coroutine, NULL);
    } else {
        qemu_coroutine_enter(qemu_coroutine_create(nbd_trip), client);
    }
}
Exemple #15
0
static void do_test_co_mutex(CoroutineEntry *entry, void *opaque)
{
    Coroutine *c1 = qemu_coroutine_create(entry, opaque);
    Coroutine *c2 = qemu_coroutine_create(entry, opaque);

    done = 0;
    qemu_coroutine_enter(c1);
    g_assert(locked);
    qemu_coroutine_enter(c2);

    /* Unlock queues c2.  It is then started automatically when c1 yields or
     * terminates.
     */
    qemu_coroutine_enter(c1);
    g_assert_cmpint(done, ==, 1);
    g_assert(locked);

    qemu_coroutine_enter(c2);
    g_assert_cmpint(done, ==, 2);
    g_assert(!locked);
}
Exemple #16
0
static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
                             const char *replaces,
                             int64_t speed, uint32_t granularity,
                             int64_t buf_size,
                             BlockdevOnError on_source_error,
                             BlockdevOnError on_target_error,
                             BlockCompletionFunc *cb,
                             void *opaque, Error **errp,
                             const BlockJobDriver *driver,
                             bool is_none_mode, BlockDriverState *base)
{
    MirrorBlockJob *s;

    if (granularity == 0) {
        granularity = bdrv_get_default_bitmap_granularity(target);
    }

    assert ((granularity & (granularity - 1)) == 0);

    if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
         on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
        !bdrv_iostatus_is_enabled(bs)) {
        error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error");
        return;
    }


    s = block_job_create(driver, bs, speed, cb, opaque, errp);
    if (!s) {
        return;
    }

    s->replaces = g_strdup(replaces);
    s->on_source_error = on_source_error;
    s->on_target_error = on_target_error;
    s->target = target;
    s->is_none_mode = is_none_mode;
    s->base = base;
    s->granularity = granularity;
    s->buf_size = MAX(buf_size, granularity);

    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
    if (!s->dirty_bitmap) {
        return;
    }
    bdrv_set_enable_write_cache(s->target, true);
    bdrv_set_on_error(s->target, on_target_error, on_target_error);
    bdrv_iostatus_enable(s->target);
    s->common.co = qemu_coroutine_create(mirror_run);
    trace_mirror_start(bs, s, s->common.co, opaque);
    qemu_coroutine_enter(s->common.co, s);
}
Exemple #17
0
static void coroutine_fn verify_entered_step_1(void *opaque)
{
    Coroutine *self = qemu_coroutine_self();
    Coroutine *coroutine;

    g_assert(qemu_coroutine_entered(self));

    coroutine = qemu_coroutine_create(verify_entered_step_2, self);
    g_assert(!qemu_coroutine_entered(coroutine));
    qemu_coroutine_enter(coroutine);
    g_assert(!qemu_coroutine_entered(coroutine));
    qemu_coroutine_enter(coroutine);
}
Exemple #18
0
static void test_yield(void)
{
    Coroutine *coroutine;
    bool done = false;
    int i = -1; /* one extra time to return from coroutine */

    coroutine = qemu_coroutine_create(yield_5_times);
    while (!done) {
        qemu_coroutine_enter(coroutine, &done);
        i++;
    }
    g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
}
Exemple #19
0
action_t *get_action(handler_func_t func) 
{
    action_t *action = (action_t *) malloc(sizeof(action_t));

    action->func = func;
    action->arg = NULL;
    action->coro = qemu_coroutine_create(func);
    action->fd = -1;
    action->flags = 0;
    action->ready = 1;
    action->next = NULL;

    return action;
}
Exemple #20
0
static void coroutine_fn nest(void *opaque)
{
    NestData *nd = opaque;

    nd->n_enter++;

    if (nd->n_enter < nd->max) {
        Coroutine *child;

        child = qemu_coroutine_create(nest);
        qemu_coroutine_enter(child, nd);
    }

    nd->n_return++;
}
Exemple #21
0
static void perf_lifecycle(void)
{
    Coroutine *coroutine;
    unsigned int i, max;
    double duration;

    max = 1000000;

    g_test_timer_start();
    for (i = 0; i < max; i++) {
        coroutine = qemu_coroutine_create(empty_coroutine);
        qemu_coroutine_enter(coroutine, NULL);
    }
    duration = g_test_timer_elapsed();

    g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
}
Exemple #22
0
static void perf_yield(void)
{
    unsigned int i, maxcycles;
    double duration;

    maxcycles = 100000000;
    i = maxcycles;
    Coroutine *coroutine = qemu_coroutine_create(yield_loop);

    g_test_timer_start();
    while (i > 0) {
        qemu_coroutine_enter(coroutine, &i);
    }
    duration = g_test_timer_elapsed();

    g_test_message("Yield %u iterations: %f s\n",
        maxcycles, duration);
}
Exemple #23
0
static int simple_bus_fdt_init(char *node_path, FDTMachineInfo *fdti)
{
    int i;
    int num_children = qemu_devtree_get_num_children(fdti->fdt, node_path,
                                                        1);
    char **children = qemu_devtree_get_children(fdti->fdt, node_path, 1);

    DB_PRINT_NP(num_children ? 0 : 1, "num child devices: %d\n", num_children);

    for (i = 0; i < num_children; i++) {
        struct FDTInitNodeArgs *init_args = g_malloc0(sizeof(*init_args));
        init_args->node_path = children[i];
        init_args->fdti = fdti;
        qemu_coroutine_enter(qemu_coroutine_create(fdt_init_node), init_args);
    }

    g_free(children);
    return 0;
}
/* Create a block job that completes with a given return code after a given
 * number of event loop iterations.  The return code is stored in the given
 * result pointer.
 *
 * The event loop iterations can either be handled automatically with a 0 delay
 * timer, or they can be stepped manually by entering the coroutine.
 */
static BlockJob *test_block_job_start(unsigned int iterations,
                                      bool use_timer,
                                      int rc, int *result)
{
    BlockDriverState *bs;
    TestBlockJob *s;
    TestBlockJobCBData *data;

    data = g_new0(TestBlockJobCBData, 1);
    bs = bdrv_new();
    s = block_job_create(&test_block_job_driver, bs, 0, test_block_job_cb,
                         data, &error_abort);
    s->iterations = iterations;
    s->use_timer = use_timer;
    s->rc = rc;
    s->result = result;
    s->common.co = qemu_coroutine_create(test_block_job_run);
    data->job = s;
    data->result = result;
    qemu_coroutine_enter(s->common.co, s);
    return &s->common;
}
Exemple #25
0
static void perf_nesting(void)
{
    unsigned int i, maxcycles, maxnesting;
    double duration;

    maxcycles = 10000;
    maxnesting = 1000;
    Coroutine *root;

    g_test_timer_start();
    for (i = 0; i < maxcycles; i++) {
        NestData nd = {
            .n_enter  = 0,
            .n_return = 0,
            .max      = maxnesting,
        };
        root = qemu_coroutine_create(nest);
        qemu_coroutine_enter(root, &nd);
    }
    duration = g_test_timer_elapsed();

    g_test_message("Nesting %u iterations of %u depth each: %f s\n",
        maxcycles, maxnesting, duration);
}

/*
 * Yield benchmark
 */

static void coroutine_fn yield_loop(void *opaque)
{
    unsigned int *counter = opaque;

    while ((*counter) > 0) {
        (*counter)--;
        qemu_coroutine_yield();
    }
}
Exemple #26
0
void commit_start(BlockDriverState *bs, BlockDriverState *base,
                  BlockDriverState *top, int64_t speed,
                  BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
                  void *opaque, Error **errp)
{
    CommitBlockJob *s;
    BlockReopenQueue *reopen_queue = NULL;
    int orig_overlay_flags;
    int orig_base_flags;
    BlockDriverState *overlay_bs;
    Error *local_err = NULL;

    if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
         on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
        !bdrv_iostatus_is_enabled(bs)) {
        error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
        return;
    }

    /* Once we support top == active layer, remove this check */
    if (top == bs) {
        error_setg(errp,
                   "Top image as the active layer is currently unsupported");
        return;
    }

    if (top == base) {
        error_setg(errp, "Invalid files for merge: top and base are the same");
        return;
    }

    overlay_bs = bdrv_find_overlay(bs, top);

    if (overlay_bs == NULL) {
        error_setg(errp, "Could not find overlay image for %s:", top->filename);
        return;
    }

    orig_base_flags    = bdrv_get_flags(base);
    orig_overlay_flags = bdrv_get_flags(overlay_bs);

    /* convert base & overlay_bs to r/w, if necessary */
    if (!(orig_base_flags & BDRV_O_RDWR)) {
        reopen_queue = bdrv_reopen_queue(reopen_queue, base,
                                         orig_base_flags | BDRV_O_RDWR);
    }
    if (!(orig_overlay_flags & BDRV_O_RDWR)) {
        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
                                         orig_overlay_flags | BDRV_O_RDWR);
    }
    if (reopen_queue) {
        bdrv_reopen_multiple(reopen_queue, &local_err);
        if (local_err != NULL) {
            error_propagate(errp, local_err);
            return;
        }
    }


    s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp);
    if (!s) {
        return;
    }

    s->base   = base;
    s->top    = top;
    s->active = bs;

    s->base_flags          = orig_base_flags;
    s->orig_overlay_flags  = orig_overlay_flags;

    s->on_error = on_error;
    s->common.co = qemu_coroutine_create(commit_run);

    trace_commit_start(bs, base, top, s, s->common.co, opaque);
    qemu_coroutine_enter(s->common.co, s);
}
void commit_start(BlockDriverState *bs, BlockDriverState *base,
                  BlockDriverState *top, int64_t speed,
                  BlockErrorAction on_error, BlockDriverCompletionFunc *cb,
                  void *opaque, Error **errp)
{
    CommitBlockJob *s;
    BlockReopenQueue *reopen_queue = NULL;
    int orig_overlay_flags;
    int orig_base_flags;
    BlockDriverState *overlay_bs;
    Error *local_err = NULL;

    if ((on_error == BLOCK_ERR_STOP_ANY ||
         on_error == BLOCK_ERR_STOP_ENOSPC) &&
        !bdrv_iostatus_is_enabled(bs)) {
        error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
        return;
    }

    /* Once we support top == active layer, remove this check */
    if (top == bs) {
        error_set(errp, QERR_TOP_IS_ACTIVE);
        return;
    }

    if (top == base) {
        error_set(errp, QERR_TOP_AND_BASE_IDENTICAL);
        return;
    }

    overlay_bs = bdrv_find_overlay(bs, top);

    if (overlay_bs == NULL) {
        error_set(errp, QERR_TOP_NOT_FOUND, top->filename);
        return;
    }

    orig_base_flags    = bdrv_get_flags(base);
    orig_overlay_flags = bdrv_get_flags(overlay_bs);

    /* convert base & overlay_bs to r/w, if necessary */
    if (!(orig_base_flags & BDRV_O_RDWR)) {
        reopen_queue = bdrv_reopen_queue(reopen_queue, base,
                                         orig_base_flags | BDRV_O_RDWR);
    }
    if (!(orig_overlay_flags & BDRV_O_RDWR)) {
        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
                                         orig_overlay_flags | BDRV_O_RDWR);
    }
    if (reopen_queue) {
        bdrv_reopen_multiple(reopen_queue, &local_err);
        if (local_err != NULL) {
            error_propagate(errp, local_err);
            return;
        }
    }


    s = block_job_create(&commit_job_type, bs, speed, cb, opaque);
    if (!s) {
        error_set(errp, QERR_DEVICE_IN_USE, bs->device_name);
        return;
    }

    s->base   = base;
    s->top    = top;
    s->active = bs;

    s->base_flags          = orig_base_flags;
    s->orig_overlay_flags  = orig_overlay_flags;

    s->on_error = on_error;
    s->common.co = qemu_coroutine_create(commit_run);

    trace_commit_start(bs, base, top, s, s->common.co, opaque);
    qemu_coroutine_enter(s->common.co, s);
}