diff options
-rw-r--r-- | aio-posix.c | 12 | ||||
-rw-r--r-- | block/linux-aio.c | 9 | ||||
-rw-r--r-- | include/block/block_int.h | 2 | ||||
-rw-r--r-- | include/qemu/coroutine.h | 13 | ||||
-rw-r--r-- | iothread.c | 3 | ||||
-rw-r--r-- | tests/libqos/virtio.c | 2 | ||||
-rw-r--r-- | tests/test-coroutine.c | 42 | ||||
-rw-r--r-- | util/qemu-coroutine.c | 5 |
8 files changed, 78 insertions, 10 deletions
diff --git a/aio-posix.c b/aio-posix.c index 43162a9f29..4ef34dd175 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -431,11 +431,13 @@ bool aio_poll(AioContext *ctx, bool blocking) assert(npfd == 0); /* fill pollfds */ - QLIST_FOREACH(node, &ctx->aio_handlers, node) { - if (!node->deleted && node->pfd.events - && !aio_epoll_enabled(ctx) - && aio_node_check(ctx, node->is_external)) { - add_pollfd(node); + + if (!aio_epoll_enabled(ctx)) { + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->pfd.events + && aio_node_check(ctx, node->is_external)) { + add_pollfd(node); + } } } diff --git a/block/linux-aio.c b/block/linux-aio.c index d4e19d444c..1685ec29a3 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -94,9 +94,12 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb) laiocb->ret = ret; if (laiocb->co) { - /* Jump and continue completion for foreign requests, don't do - * anything for current request, it will be completed shortly. */ - if (laiocb->co != qemu_coroutine_self()) { + /* If the coroutine is already entered it must be in ioq_submit() and + * will notice laio->ret has been filled in when it eventually runs + * later. Coroutines cannot be entered recursively so avoid doing + * that! + */ + if (!qemu_coroutine_entered(laiocb->co)) { qemu_coroutine_enter(laiocb->co); } } else { diff --git a/include/block/block_int.h b/include/block/block_int.h index ef3c047cb3..3e79228eb0 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -722,7 +722,7 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, * @errp: Error object. * * Start a mirroring operation on @bs. Clusters that are allocated - * in @bs will be written to @bs until the job is cancelled or + * in @bs will be written to @target until the job is cancelled or * manually completed. At the end of a successful mirroring job, * @bs will be switched to read from @target. */ diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 29a20782f0..e6a60d55fd 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -92,6 +92,19 @@ Coroutine *coroutine_fn qemu_coroutine_self(void); */ bool qemu_in_coroutine(void); +/** + * Return true if the coroutine is currently entered + * + * A coroutine is "entered" if it has not yielded from the current + * qemu_coroutine_enter() call used to run it. This does not mean that the + * coroutine is currently executing code since it may have transferred control + * to another coroutine using qemu_coroutine_enter(). + * + * When several coroutines enter each other there may be no way to know which + * ones have already been entered. In such situations this function can be + * used to avoid recursively entering coroutines. + */ +bool qemu_coroutine_entered(Coroutine *co); /** diff --git a/iothread.c b/iothread.c index fb08a60b4b..fbeb8deb38 100644 --- a/iothread.c +++ b/iothread.c @@ -75,6 +75,9 @@ static void iothread_instance_finalize(Object *obj) iothread_stop(obj, NULL); qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock); + if (!iothread->ctx) { + return; + } aio_context_unref(iothread->ctx); } diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 37ff860c16..105bccecaa 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -147,7 +147,7 @@ void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr) for (i = 0; i < vq->size - 1; i++) { /* vq->desc[i].addr */ - writew(vq->desc + (16 * i), 0); + writeq(vq->desc + (16 * i), 0); /* vq->desc[i].next */ writew(vq->desc + (16 * i) + 14, i + 1); } diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index 6431dd6d7c..abd97c23c1 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -53,6 +53,47 @@ static void test_self(void) } /* + * Check that qemu_coroutine_entered() works + */ + +static void coroutine_fn verify_entered_step_2(void *opaque) +{ + Coroutine *caller = (Coroutine *)opaque; + + g_assert(qemu_coroutine_entered(caller)); + g_assert(qemu_coroutine_entered(qemu_coroutine_self())); + qemu_coroutine_yield(); + + /* Once more to check it still works after yielding */ + g_assert(qemu_coroutine_entered(caller)); + g_assert(qemu_coroutine_entered(qemu_coroutine_self())); + qemu_coroutine_yield(); +} + +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); +} + +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); +} + +/* * Check that coroutines may nest multiple levels */ @@ -389,6 +430,7 @@ int main(int argc, char **argv) g_test_add_func("/basic/yield", test_yield); g_test_add_func("/basic/nesting", test_nesting); g_test_add_func("/basic/self", test_self); + g_test_add_func("/basic/entered", test_entered); g_test_add_func("/basic/in_coroutine", test_in_coroutine); g_test_add_func("/basic/order", test_order); if (g_test_perf()) { diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 3cbf225487..737bffa984 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -146,3 +146,8 @@ void coroutine_fn qemu_coroutine_yield(void) self->caller = NULL; qemu_coroutine_switch(self, to, COROUTINE_YIELD); } + +bool qemu_coroutine_entered(Coroutine *co) +{ + return co->caller; +} |