| 1 | /* |
| 2 | * QEMU block layer thread pool |
| 3 | * |
| 4 | * Copyright IBM, Corp. 2008 |
| 5 | * Copyright Red Hat, Inc. 2012 |
| 6 | * |
| 7 | * Authors: |
| 8 | * Anthony Liguori <aliguori@us.ibm.com> |
| 9 | * Paolo Bonzini <pbonzini@redhat.com> |
| 10 | * |
| 11 | * This work is licensed under the terms of the GNU GPL, version 2. See |
| 12 | * the COPYING file in the top-level directory. |
| 13 | * |
| 14 | * Contributions after 2012-01-13 are licensed under the terms of the |
| 15 | * GNU GPL, version 2 or (at your option) any later version. |
| 16 | */ |
| 17 | #include "qemu/osdep.h" |
| 18 | #include "qemu/defer-call.h" |
| 19 | #include "qemu/queue.h" |
| 20 | #include "qemu/thread.h" |
| 21 | #include "qemu/atomic.h" |
| 22 | #include "qemu/coroutine.h" |
| 23 | #include "trace.h" |
| 24 | #include "block/thread-pool.h" |
| 25 | #include "qemu/main-loop.h" |
| 26 | |
| 27 | static void do_spawn_thread(ThreadPoolAio *pool); |
| 28 | |
| 29 | typedef struct ThreadPoolElementAio ThreadPoolElementAio; |
| 30 | |
| 31 | enum ThreadState { |
| 32 | THREAD_QUEUED, |
| 33 | THREAD_ACTIVE, |
| 34 | THREAD_DONE, |
| 35 | }; |
| 36 | |
| 37 | struct ThreadPoolElementAio { |
| 38 | BlockAIOCB common; |
| 39 | ThreadPoolAio *pool; |
| 40 | ThreadPoolFunc *func; |
| 41 | void *arg; |
| 42 | |
| 43 | /* |
| 44 | * Accessed with atomics. Moving state out of THREAD_QUEUED is |
| 45 | * protected by pool->lock and only the worker thread can move |
| 46 | * the state from THREAD_ACTIVE to THREAD_DONE. |
| 47 | * |
| 48 | * When state is THREAD_DONE, ret must have been written already. |
| 49 | * Use acquire/release ordering when reading/writing ret as well. |
| 50 | */ |
| 51 | enum ThreadState state; |
| 52 | int ret; |
| 53 | |
| 54 | /* Access to this list is protected by lock. */ |
| 55 | QTAILQ_ENTRY(ThreadPoolElementAio) reqs; |
| 56 | |
| 57 | /* This list is only written by the thread pool's mother thread. */ |
| 58 | QLIST_ENTRY(ThreadPoolElementAio) all; |
| 59 | }; |
| 60 | |
| 61 | struct ThreadPoolAio { |
| 62 | AioContext *ctx; |
| 63 | QEMUBH *completion_bh; |
| 64 | QemuMutex lock; |
| 65 | QemuCond worker_stopped; |
| 66 | QemuCond request_cond; |
| 67 | QEMUBH *new_thread_bh; |
| 68 | |
| 69 | /* The following variables are only accessed from one AioContext. */ |
| 70 | QLIST_HEAD(, ThreadPoolElementAio) head; |
| 71 | |
| 72 | /* The following variables are protected by lock. */ |
| 73 | QTAILQ_HEAD(, ThreadPoolElementAio) request_list; |
| 74 | int cur_threads; |
| 75 | int idle_threads; |
| 76 | int new_threads; /* backlog of threads we need to create */ |
| 77 | int pending_threads; /* threads created but not running yet */ |
| 78 | int min_threads; |
| 79 | int max_threads; |
| 80 | }; |
| 81 | |
| 82 | static void *worker_thread(void *opaque) |
| 83 | { |
| 84 | ThreadPoolAio *pool = opaque; |
| 85 | |
| 86 | qemu_mutex_lock(&pool->lock); |
| 87 | pool->pending_threads--; |
| 88 | do_spawn_thread(pool); |
| 89 | |
| 90 | while (pool->cur_threads <= pool->max_threads) { |
| 91 | ThreadPoolElementAio *req; |
| 92 | int ret; |
| 93 | |
| 94 | if (QTAILQ_EMPTY(&pool->request_list)) { |
| 95 | pool->idle_threads++; |
| 96 | ret = qemu_cond_timedwait(&pool->request_cond, &pool->lock, 10000); |
| 97 | pool->idle_threads--; |
| 98 | if (ret == 0 && |
| 99 | QTAILQ_EMPTY(&pool->request_list) && |
| 100 | pool->cur_threads > pool->min_threads) { |
| 101 | /* Timed out + no work to do + no need for warm threads = exit. */ |
| 102 | break; |
| 103 | } |
| 104 | /* |
| 105 | * Even if there was some work to do, check if there aren't |
| 106 | * too many worker threads before picking it up. |
| 107 | */ |
| 108 | continue; |
| 109 | } |
| 110 | |
| 111 | req = QTAILQ_FIRST(&pool->request_list); |
| 112 | QTAILQ_REMOVE(&pool->request_list, req, reqs); |
| 113 | qatomic_set(&req->state, THREAD_ACTIVE); |
| 114 | qemu_mutex_unlock(&pool->lock); |
| 115 | |
| 116 | ret = req->func(req->arg); |
| 117 | |
| 118 | qatomic_set(&req->ret, ret); |
| 119 | /* _release to write ret before state. */ |
| 120 | qatomic_store_release(&req->state, THREAD_DONE); |
| 121 | |
| 122 | qemu_bh_schedule(pool->completion_bh); |
| 123 | qemu_mutex_lock(&pool->lock); |
| 124 | } |
| 125 | |
| 126 | pool->cur_threads--; |
| 127 | qemu_cond_signal(&pool->worker_stopped); |
| 128 | |
| 129 | /* |
| 130 | * Wake up another thread, in case we got a wakeup but decided |
| 131 | * to exit due to pool->cur_threads > pool->max_threads. |
| 132 | */ |
| 133 | qemu_cond_signal(&pool->request_cond); |
| 134 | qemu_mutex_unlock(&pool->lock); |
| 135 | return NULL; |
| 136 | } |
| 137 | |
| 138 | static void do_spawn_thread(ThreadPoolAio *pool) |
| 139 | { |
| 140 | QemuThread t; |
| 141 | |
| 142 | /* Runs with lock taken. */ |
| 143 | if (!pool->new_threads) { |
| 144 | return; |
| 145 | } |
| 146 | |
| 147 | pool->new_threads--; |
| 148 | pool->pending_threads++; |
| 149 | |
| 150 | qemu_thread_create(&t, "worker", worker_thread, pool, QEMU_THREAD_DETACHED); |
| 151 | } |
| 152 | |
| 153 | static void spawn_thread_bh_fn(void *opaque) |
| 154 | { |
| 155 | ThreadPoolAio *pool = opaque; |
| 156 | |
| 157 | qemu_mutex_lock(&pool->lock); |
| 158 | do_spawn_thread(pool); |
| 159 | qemu_mutex_unlock(&pool->lock); |
| 160 | } |
| 161 | |
| 162 | static void spawn_thread(ThreadPoolAio *pool) |
| 163 | { |
| 164 | pool->cur_threads++; |
| 165 | pool->new_threads++; |
| 166 | /* If there are threads being created, they will spawn new workers, so |
| 167 | * we don't spend time creating many threads in a loop holding a mutex or |
| 168 | * starving the current vcpu. |
| 169 | * |
| 170 | * If there are no idle threads, ask the main thread to create one, so we |
| 171 | * inherit the correct affinity instead of the vcpu affinity. |
| 172 | */ |
| 173 | if (!pool->pending_threads) { |
| 174 | qemu_bh_schedule(pool->new_thread_bh); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | static void thread_pool_completion_bh(void *opaque) |
| 179 | { |
| 180 | ThreadPoolAio *pool = opaque; |
| 181 | ThreadPoolElementAio *elem, *next; |
| 182 | |
| 183 | defer_call_begin(); /* cb() may use defer_call() to coalesce work */ |
| 184 | |
| 185 | restart: |
| 186 | QLIST_FOREACH_SAFE(elem, &pool->head, all, next) { |
| 187 | /* _acquire to read state before ret. */ |
| 188 | if (qatomic_load_acquire(&elem->state) != THREAD_DONE) { |
| 189 | continue; |
| 190 | } |
| 191 | |
| 192 | trace_thread_pool_complete_aio(pool, elem, elem->common.opaque, |
| 193 | elem->ret); |
| 194 | QLIST_REMOVE(elem, all); |
| 195 | |
| 196 | if (elem->common.cb) { |
| 197 | /* Schedule ourselves in case elem->common.cb() calls aio_poll() to |
| 198 | * wait for another request that completed at the same time. |
| 199 | */ |
| 200 | qemu_bh_schedule(pool->completion_bh); |
| 201 | |
| 202 | elem->common.cb(elem->common.opaque, elem->ret); |
| 203 | |
| 204 | /* We can safely cancel the completion_bh here regardless of someone |
| 205 | * else having scheduled it meanwhile because we reenter the |
| 206 | * completion function anyway (goto restart). |
| 207 | */ |
| 208 | qemu_bh_cancel(pool->completion_bh); |
| 209 | |
| 210 | qemu_aio_unref(elem); |
| 211 | goto restart; |
| 212 | } else { |
| 213 | qemu_aio_unref(elem); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | defer_call_end(); |
| 218 | } |
| 219 | |
| 220 | static void thread_pool_cancel(BlockAIOCB *acb) |
| 221 | { |
| 222 | ThreadPoolElementAio *elem = (ThreadPoolElementAio *)acb; |
| 223 | ThreadPoolAio *pool = elem->pool; |
| 224 | |
| 225 | trace_thread_pool_cancel_aio(elem, elem->common.opaque); |
| 226 | |
| 227 | QEMU_LOCK_GUARD(&pool->lock); |
| 228 | if (qatomic_read(&elem->state) == THREAD_QUEUED) { |
| 229 | QTAILQ_REMOVE(&pool->request_list, elem, reqs); |
| 230 | qemu_bh_schedule(pool->completion_bh); |
| 231 | |
| 232 | qatomic_set(&elem->ret, -ECANCELED); |
| 233 | qatomic_store_release(&elem->state, THREAD_DONE); |
| 234 | } |
| 235 | |
| 236 | } |
| 237 | |
| 238 | static const AIOCBInfo thread_pool_aiocb_info = { |
| 239 | .aiocb_size = sizeof(ThreadPoolElementAio), |
| 240 | .cancel_async = thread_pool_cancel, |
| 241 | }; |
| 242 | |
| 243 | BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, |
| 244 | BlockCompletionFunc *cb, void *opaque) |
| 245 | { |
| 246 | ThreadPoolElementAio *req; |
| 247 | AioContext *ctx = qemu_get_current_aio_context(); |
| 248 | ThreadPoolAio *pool = aio_get_thread_pool(ctx); |
| 249 | |
| 250 | /* Assert that the thread submitting work is the same running the pool */ |
| 251 | assert(pool->ctx == qemu_get_current_aio_context()); |
| 252 | |
| 253 | req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); |
| 254 | req->func = func; |
| 255 | req->arg = arg; |
| 256 | req->state = THREAD_QUEUED; |
| 257 | req->pool = pool; |
| 258 | |
| 259 | QLIST_INSERT_HEAD(&pool->head, req, all); |
| 260 | |
| 261 | trace_thread_pool_submit_aio(pool, req, arg); |
| 262 | |
| 263 | qemu_mutex_lock(&pool->lock); |
| 264 | if (pool->idle_threads == 0 && pool->cur_threads < pool->max_threads) { |
| 265 | spawn_thread(pool); |
| 266 | } |
| 267 | QTAILQ_INSERT_TAIL(&pool->request_list, req, reqs); |
| 268 | qemu_mutex_unlock(&pool->lock); |
| 269 | qemu_cond_signal(&pool->request_cond); |
| 270 | return &req->common; |
| 271 | } |
| 272 | |
| 273 | typedef struct ThreadPoolCo { |
| 274 | Coroutine *co; |
| 275 | int ret; |
| 276 | } ThreadPoolCo; |
| 277 | |
| 278 | static void thread_pool_co_cb(void *opaque, int ret) |
| 279 | { |
| 280 | ThreadPoolCo *co = opaque; |
| 281 | |
| 282 | co->ret = ret; |
| 283 | aio_co_wake(co->co); |
| 284 | } |
| 285 | |
| 286 | int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg) |
| 287 | { |
| 288 | ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS }; |
| 289 | assert(qemu_in_coroutine()); |
| 290 | thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc); |
| 291 | qemu_coroutine_yield(); |
| 292 | return tpc.ret; |
| 293 | } |
| 294 | |
| 295 | void thread_pool_update_params(ThreadPoolAio *pool, AioContext *ctx) |
| 296 | { |
| 297 | qemu_mutex_lock(&pool->lock); |
| 298 | |
| 299 | pool->min_threads = ctx->thread_pool_min; |
| 300 | pool->max_threads = ctx->thread_pool_max; |
| 301 | |
| 302 | /* |
| 303 | * We either have to: |
| 304 | * - Increase the number available of threads until over the min_threads |
| 305 | * threshold. |
| 306 | * - Bump the worker threads so that they exit, until under the max_threads |
| 307 | * threshold. |
| 308 | * - Do nothing. The current number of threads fall in between the min and |
| 309 | * max thresholds. We'll let the pool manage itself. |
| 310 | */ |
| 311 | for (int i = pool->cur_threads; i < pool->min_threads; i++) { |
| 312 | spawn_thread(pool); |
| 313 | } |
| 314 | |
| 315 | for (int i = pool->cur_threads; i > pool->max_threads; i--) { |
| 316 | qemu_cond_signal(&pool->request_cond); |
| 317 | } |
| 318 | |
| 319 | qemu_mutex_unlock(&pool->lock); |
| 320 | } |
| 321 | |
| 322 | static void thread_pool_init_one(ThreadPoolAio *pool, AioContext *ctx) |
| 323 | { |
| 324 | if (!ctx) { |
| 325 | ctx = qemu_get_aio_context(); |
| 326 | } |
| 327 | |
| 328 | memset(pool, 0, sizeof(*pool)); |
| 329 | pool->ctx = ctx; |
| 330 | pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool); |
| 331 | qemu_mutex_init(&pool->lock); |
| 332 | qemu_cond_init(&pool->worker_stopped); |
| 333 | qemu_cond_init(&pool->request_cond); |
| 334 | pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); |
| 335 | |
| 336 | QLIST_INIT(&pool->head); |
| 337 | QTAILQ_INIT(&pool->request_list); |
| 338 | |
| 339 | thread_pool_update_params(pool, ctx); |
| 340 | } |
| 341 | |
| 342 | ThreadPoolAio *thread_pool_new_aio(AioContext *ctx) |
| 343 | { |
| 344 | ThreadPoolAio *pool = g_new(ThreadPoolAio, 1); |
| 345 | thread_pool_init_one(pool, ctx); |
| 346 | return pool; |
| 347 | } |
| 348 | |
| 349 | void thread_pool_free_aio(ThreadPoolAio *pool) |
| 350 | { |
| 351 | if (!pool) { |
| 352 | return; |
| 353 | } |
| 354 | |
| 355 | assert(QLIST_EMPTY(&pool->head)); |
| 356 | |
| 357 | qemu_mutex_lock(&pool->lock); |
| 358 | |
| 359 | /* Stop new threads from spawning */ |
| 360 | qemu_bh_delete(pool->new_thread_bh); |
| 361 | pool->cur_threads -= pool->new_threads; |
| 362 | pool->new_threads = 0; |
| 363 | |
| 364 | /* Wait for worker threads to terminate */ |
| 365 | pool->max_threads = 0; |
| 366 | qemu_cond_broadcast(&pool->request_cond); |
| 367 | while (pool->cur_threads > 0) { |
| 368 | qemu_cond_wait(&pool->worker_stopped, &pool->lock); |
| 369 | } |
| 370 | |
| 371 | qemu_mutex_unlock(&pool->lock); |
| 372 | |
| 373 | qemu_bh_delete(pool->completion_bh); |
| 374 | qemu_cond_destroy(&pool->request_cond); |
| 375 | qemu_cond_destroy(&pool->worker_stopped); |
| 376 | qemu_mutex_destroy(&pool->lock); |
| 377 | g_free(pool); |
| 378 | } |
| 379 | |
| 380 | struct ThreadPool { |
| 381 | GThreadPool *t; |
| 382 | size_t cur_work; |
| 383 | QemuMutex cur_work_lock; |
| 384 | QemuCond all_finished_cond; |
| 385 | }; |
| 386 | |
| 387 | typedef struct { |
| 388 | ThreadPoolFunc *func; |
| 389 | void *opaque; |
| 390 | GDestroyNotify opaque_destroy; |
| 391 | } ThreadPoolElement; |
| 392 | |
| 393 | static void thread_pool_func(gpointer data, gpointer user_data) |
| 394 | { |
| 395 | ThreadPool *pool = user_data; |
| 396 | g_autofree ThreadPoolElement *el = data; |
| 397 | |
| 398 | el->func(el->opaque); |
| 399 | |
| 400 | if (el->opaque_destroy) { |
| 401 | el->opaque_destroy(el->opaque); |
| 402 | } |
| 403 | |
| 404 | QEMU_LOCK_GUARD(&pool->cur_work_lock); |
| 405 | |
| 406 | assert(pool->cur_work > 0); |
| 407 | pool->cur_work--; |
| 408 | |
| 409 | if (pool->cur_work == 0) { |
| 410 | qemu_cond_signal(&pool->all_finished_cond); |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | ThreadPool *thread_pool_new(void) |
| 415 | { |
| 416 | ThreadPool *pool = g_new(ThreadPool, 1); |
| 417 | |
| 418 | pool->cur_work = 0; |
| 419 | qemu_mutex_init(&pool->cur_work_lock); |
| 420 | qemu_cond_init(&pool->all_finished_cond); |
| 421 | |
| 422 | pool->t = g_thread_pool_new(thread_pool_func, pool, 0, TRUE, NULL); |
| 423 | /* |
| 424 | * g_thread_pool_new() can only return errors if initial thread(s) |
| 425 | * creation fails but we ask for 0 initial threads above. |
| 426 | */ |
| 427 | assert(pool->t); |
| 428 | |
| 429 | return pool; |
| 430 | } |
| 431 | |
| 432 | void thread_pool_free(ThreadPool *pool) |
| 433 | { |
| 434 | /* |
| 435 | * With _wait = TRUE this effectively waits for all |
| 436 | * previously submitted work to complete first. |
| 437 | */ |
| 438 | g_thread_pool_free(pool->t, FALSE, TRUE); |
| 439 | |
| 440 | qemu_cond_destroy(&pool->all_finished_cond); |
| 441 | qemu_mutex_destroy(&pool->cur_work_lock); |
| 442 | |
| 443 | g_free(pool); |
| 444 | } |
| 445 | |
| 446 | void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, |
| 447 | void *opaque, GDestroyNotify opaque_destroy) |
| 448 | { |
| 449 | ThreadPoolElement *el = g_new(ThreadPoolElement, 1); |
| 450 | |
| 451 | el->func = func; |
| 452 | el->opaque = opaque; |
| 453 | el->opaque_destroy = opaque_destroy; |
| 454 | |
| 455 | WITH_QEMU_LOCK_GUARD(&pool->cur_work_lock) { |
| 456 | pool->cur_work++; |
| 457 | } |
| 458 | |
| 459 | /* |
| 460 | * Ignore the return value since this function can only return errors |
| 461 | * if creation of an additional thread fails but even in this case the |
| 462 | * provided work is still getting queued (just for the existing threads). |
| 463 | */ |
| 464 | g_thread_pool_push(pool->t, el, NULL); |
| 465 | } |
| 466 | |
| 467 | void thread_pool_submit_immediate(ThreadPool *pool, ThreadPoolFunc *func, |
| 468 | void *opaque, GDestroyNotify opaque_destroy) |
| 469 | { |
| 470 | thread_pool_submit(pool, func, opaque, opaque_destroy); |
| 471 | thread_pool_adjust_max_threads_to_work(pool); |
| 472 | } |
| 473 | |
| 474 | void thread_pool_wait(ThreadPool *pool) |
| 475 | { |
| 476 | QEMU_LOCK_GUARD(&pool->cur_work_lock); |
| 477 | |
| 478 | while (pool->cur_work > 0) { |
| 479 | qemu_cond_wait(&pool->all_finished_cond, |
| 480 | &pool->cur_work_lock); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | bool thread_pool_set_max_threads(ThreadPool *pool, |
| 485 | int max_threads) |
| 486 | { |
| 487 | assert(max_threads > 0); |
| 488 | |
| 489 | return g_thread_pool_set_max_threads(pool->t, max_threads, NULL); |
| 490 | } |
| 491 | |
| 492 | bool thread_pool_adjust_max_threads_to_work(ThreadPool *pool) |
| 493 | { |
| 494 | QEMU_LOCK_GUARD(&pool->cur_work_lock); |
| 495 | |
| 496 | return thread_pool_set_max_threads(pool, MAX(pool->cur_work, 1)); |
| 497 | } |