When curl_co_preadv is called it sets up an ACB block which points to current coroutine. It will then call curl_setup_preadv and wait until request is completed by polling return status and yeilding:
curl_setup_preadv(bs, &acb); while (acb.ret == -EINPROGRESS) { qemu_coroutine_yield(); } curl_setup_preadv will ask libcurl to handle read request and to use curl_read_cb as completion callback for each completed chunk. When curl_read_cb sees request as completed it will attempt to wake up issuing coroutine assuming that yield was called previously: qemu_mutex_unlock(&s->s->mutex); aio_co_wake(acb->co); qemu_mutex_lock(&s->s->mutex); However if request is short enough (< 16K in our test) curl_read_cb will be called right away before returning from libcurl to curl_setup_preadv. Request will be completed before yield was called from the same coroutine, which asserts in aio_co_enter. This change attempts to fix this by waking completion coroutine only if it is not the current one. Signed-off-by: Evgeny Yakovlev <wr...@yandex-team.ru> --- block/curl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/curl.c b/block/curl.c index 2a244e2..b1106d6 100644 --- a/block/curl.c +++ b/block/curl.c @@ -271,9 +271,12 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque) acb->ret = 0; s->acb[i] = NULL; - qemu_mutex_unlock(&s->s->mutex); - aio_co_wake(acb->co); - qemu_mutex_lock(&s->s->mutex); + + if (qemu_coroutine_self() != acb->co) { + qemu_mutex_unlock(&s->s->mutex); + aio_co_wake(acb->co); + qemu_mutex_lock(&s->s->mutex); + } } } -- 2.7.4