16e9b225fSVladimir Sementsov-Ogievskiy /*
26e9b225fSVladimir Sementsov-Ogievskiy * Aio tasks loops
36e9b225fSVladimir Sementsov-Ogievskiy *
46e9b225fSVladimir Sementsov-Ogievskiy * Copyright (c) 2019 Virtuozzo International GmbH.
56e9b225fSVladimir Sementsov-Ogievskiy *
66e9b225fSVladimir Sementsov-Ogievskiy * Permission is hereby granted, free of charge, to any person obtaining a copy
76e9b225fSVladimir Sementsov-Ogievskiy * of this software and associated documentation files (the "Software"), to deal
86e9b225fSVladimir Sementsov-Ogievskiy * in the Software without restriction, including without limitation the rights
96e9b225fSVladimir Sementsov-Ogievskiy * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
106e9b225fSVladimir Sementsov-Ogievskiy * copies of the Software, and to permit persons to whom the Software is
116e9b225fSVladimir Sementsov-Ogievskiy * furnished to do so, subject to the following conditions:
126e9b225fSVladimir Sementsov-Ogievskiy *
136e9b225fSVladimir Sementsov-Ogievskiy * The above copyright notice and this permission notice shall be included in
146e9b225fSVladimir Sementsov-Ogievskiy * all copies or substantial portions of the Software.
156e9b225fSVladimir Sementsov-Ogievskiy *
166e9b225fSVladimir Sementsov-Ogievskiy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176e9b225fSVladimir Sementsov-Ogievskiy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186e9b225fSVladimir Sementsov-Ogievskiy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
196e9b225fSVladimir Sementsov-Ogievskiy * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
206e9b225fSVladimir Sementsov-Ogievskiy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216e9b225fSVladimir Sementsov-Ogievskiy * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
226e9b225fSVladimir Sementsov-Ogievskiy * THE SOFTWARE.
236e9b225fSVladimir Sementsov-Ogievskiy */
246e9b225fSVladimir Sementsov-Ogievskiy
256e9b225fSVladimir Sementsov-Ogievskiy #include "qemu/osdep.h"
266e9b225fSVladimir Sementsov-Ogievskiy #include "block/aio.h"
276e9b225fSVladimir Sementsov-Ogievskiy #include "block/aio_task.h"
286e9b225fSVladimir Sementsov-Ogievskiy
296e9b225fSVladimir Sementsov-Ogievskiy struct AioTaskPool {
306e9b225fSVladimir Sementsov-Ogievskiy Coroutine *main_co;
316e9b225fSVladimir Sementsov-Ogievskiy int status;
326e9b225fSVladimir Sementsov-Ogievskiy int max_busy_tasks;
336e9b225fSVladimir Sementsov-Ogievskiy int busy_tasks;
346e9b225fSVladimir Sementsov-Ogievskiy bool waiting;
356e9b225fSVladimir Sementsov-Ogievskiy };
366e9b225fSVladimir Sementsov-Ogievskiy
aio_task_co(void * opaque)376e9b225fSVladimir Sementsov-Ogievskiy static void coroutine_fn aio_task_co(void *opaque)
386e9b225fSVladimir Sementsov-Ogievskiy {
396e9b225fSVladimir Sementsov-Ogievskiy AioTask *task = opaque;
406e9b225fSVladimir Sementsov-Ogievskiy AioTaskPool *pool = task->pool;
416e9b225fSVladimir Sementsov-Ogievskiy
426e9b225fSVladimir Sementsov-Ogievskiy assert(pool->busy_tasks < pool->max_busy_tasks);
436e9b225fSVladimir Sementsov-Ogievskiy pool->busy_tasks++;
446e9b225fSVladimir Sementsov-Ogievskiy
456e9b225fSVladimir Sementsov-Ogievskiy task->ret = task->func(task);
466e9b225fSVladimir Sementsov-Ogievskiy
476e9b225fSVladimir Sementsov-Ogievskiy pool->busy_tasks--;
486e9b225fSVladimir Sementsov-Ogievskiy
496e9b225fSVladimir Sementsov-Ogievskiy if (task->ret < 0 && pool->status == 0) {
506e9b225fSVladimir Sementsov-Ogievskiy pool->status = task->ret;
516e9b225fSVladimir Sementsov-Ogievskiy }
526e9b225fSVladimir Sementsov-Ogievskiy
536e9b225fSVladimir Sementsov-Ogievskiy g_free(task);
546e9b225fSVladimir Sementsov-Ogievskiy
556e9b225fSVladimir Sementsov-Ogievskiy if (pool->waiting) {
566e9b225fSVladimir Sementsov-Ogievskiy pool->waiting = false;
576e9b225fSVladimir Sementsov-Ogievskiy aio_co_wake(pool->main_co);
586e9b225fSVladimir Sementsov-Ogievskiy }
596e9b225fSVladimir Sementsov-Ogievskiy }
606e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_wait_one(AioTaskPool * pool)616e9b225fSVladimir Sementsov-Ogievskiy void coroutine_fn aio_task_pool_wait_one(AioTaskPool *pool)
626e9b225fSVladimir Sementsov-Ogievskiy {
636e9b225fSVladimir Sementsov-Ogievskiy assert(pool->busy_tasks > 0);
646e9b225fSVladimir Sementsov-Ogievskiy assert(qemu_coroutine_self() == pool->main_co);
656e9b225fSVladimir Sementsov-Ogievskiy
666e9b225fSVladimir Sementsov-Ogievskiy pool->waiting = true;
676e9b225fSVladimir Sementsov-Ogievskiy qemu_coroutine_yield();
686e9b225fSVladimir Sementsov-Ogievskiy
696e9b225fSVladimir Sementsov-Ogievskiy assert(!pool->waiting);
706e9b225fSVladimir Sementsov-Ogievskiy assert(pool->busy_tasks < pool->max_busy_tasks);
716e9b225fSVladimir Sementsov-Ogievskiy }
726e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_wait_slot(AioTaskPool * pool)736e9b225fSVladimir Sementsov-Ogievskiy void coroutine_fn aio_task_pool_wait_slot(AioTaskPool *pool)
746e9b225fSVladimir Sementsov-Ogievskiy {
756e9b225fSVladimir Sementsov-Ogievskiy if (pool->busy_tasks < pool->max_busy_tasks) {
766e9b225fSVladimir Sementsov-Ogievskiy return;
776e9b225fSVladimir Sementsov-Ogievskiy }
786e9b225fSVladimir Sementsov-Ogievskiy
796e9b225fSVladimir Sementsov-Ogievskiy aio_task_pool_wait_one(pool);
806e9b225fSVladimir Sementsov-Ogievskiy }
816e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_wait_all(AioTaskPool * pool)826e9b225fSVladimir Sementsov-Ogievskiy void coroutine_fn aio_task_pool_wait_all(AioTaskPool *pool)
836e9b225fSVladimir Sementsov-Ogievskiy {
846e9b225fSVladimir Sementsov-Ogievskiy while (pool->busy_tasks > 0) {
856e9b225fSVladimir Sementsov-Ogievskiy aio_task_pool_wait_one(pool);
866e9b225fSVladimir Sementsov-Ogievskiy }
876e9b225fSVladimir Sementsov-Ogievskiy }
886e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_start_task(AioTaskPool * pool,AioTask * task)896e9b225fSVladimir Sementsov-Ogievskiy void coroutine_fn aio_task_pool_start_task(AioTaskPool *pool, AioTask *task)
906e9b225fSVladimir Sementsov-Ogievskiy {
916e9b225fSVladimir Sementsov-Ogievskiy aio_task_pool_wait_slot(pool);
926e9b225fSVladimir Sementsov-Ogievskiy
936e9b225fSVladimir Sementsov-Ogievskiy task->pool = pool;
946e9b225fSVladimir Sementsov-Ogievskiy qemu_coroutine_enter(qemu_coroutine_create(aio_task_co, task));
956e9b225fSVladimir Sementsov-Ogievskiy }
966e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_new(int max_busy_tasks)976e9b225fSVladimir Sementsov-Ogievskiy AioTaskPool *coroutine_fn aio_task_pool_new(int max_busy_tasks)
986e9b225fSVladimir Sementsov-Ogievskiy {
996e9b225fSVladimir Sementsov-Ogievskiy AioTaskPool *pool = g_new0(AioTaskPool, 1);
1006e9b225fSVladimir Sementsov-Ogievskiy
101*a9515df4SStefano Garzarella assert(max_busy_tasks > 0);
102*a9515df4SStefano Garzarella
1036e9b225fSVladimir Sementsov-Ogievskiy pool->main_co = qemu_coroutine_self();
1046e9b225fSVladimir Sementsov-Ogievskiy pool->max_busy_tasks = max_busy_tasks;
1056e9b225fSVladimir Sementsov-Ogievskiy
1066e9b225fSVladimir Sementsov-Ogievskiy return pool;
1076e9b225fSVladimir Sementsov-Ogievskiy }
1086e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_free(AioTaskPool * pool)1096e9b225fSVladimir Sementsov-Ogievskiy void aio_task_pool_free(AioTaskPool *pool)
1106e9b225fSVladimir Sementsov-Ogievskiy {
1116e9b225fSVladimir Sementsov-Ogievskiy g_free(pool);
1126e9b225fSVladimir Sementsov-Ogievskiy }
1136e9b225fSVladimir Sementsov-Ogievskiy
aio_task_pool_status(AioTaskPool * pool)1146e9b225fSVladimir Sementsov-Ogievskiy int aio_task_pool_status(AioTaskPool *pool)
1156e9b225fSVladimir Sementsov-Ogievskiy {
1166e9b225fSVladimir Sementsov-Ogievskiy if (!pool) {
1176e9b225fSVladimir Sementsov-Ogievskiy return 0; /* Sugar for lazy allocation of aio pool */
1186e9b225fSVladimir Sementsov-Ogievskiy }
1196e9b225fSVladimir Sementsov-Ogievskiy
1206e9b225fSVladimir Sementsov-Ogievskiy return pool->status;
1216e9b225fSVladimir Sementsov-Ogievskiy }
122