| 245 | } |
| 246 | |
| 247 | void AsyncLoader::wait() |
| 248 | { |
| 249 | // Because job can create new jobs in other pools we have to recheck in cycle. |
| 250 | // Also wait for all workers to finish to avoid races on `pool.workers`, |
| 251 | // which can decrease even after all jobs are already finished. |
| 252 | std::unique_lock lock{mutex}; |
| 253 | while (!scheduled_jobs.empty() || hasWorker(lock)) |
| 254 | { |
| 255 | lock.unlock(); |
| 256 | for (auto & p : pools) |
| 257 | p.thread_pool->wait(); |
| 258 | lock.lock(); |
| 259 | |
| 260 | // If there is no way for all jobs to finish, throw LOGICAL_ERROR instead of deadlock |
| 261 | if (!scheduled_jobs.empty() && !hasWorker(lock)) |
| 262 | { |
| 263 | std::vector<String> names; |
| 264 | names.reserve(scheduled_jobs.size()); |
| 265 | for (const auto & [job, _] : scheduled_jobs) |
| 266 | names.push_back(job->name); |
| 267 | LOG_ERROR(log, "Waiting for load jobs to finish while being stopped: {}.", fmt::join(names, ", ")); |
| 268 | abort(); |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | void AsyncLoader::shutdown() |
| 274 | { |
no test coverage detected