void BLI_task_pool_work_and_wait(TaskPool *pool) { TaskScheduler *scheduler = pool->scheduler; BLI_mutex_lock(&pool->num_mutex); while (pool->num != 0) { Task *task, *work_task = NULL; bool found_task = false; BLI_mutex_unlock(&pool->num_mutex); BLI_mutex_lock(&scheduler->queue_mutex); /* find task from this pool. if we get a task from another pool, * we can get into deadlock */ for (task = scheduler->queue.first; task; task = task->next) { if (task->pool == pool) { work_task = task; found_task = true; BLI_remlink(&scheduler->queue, task); break; } } BLI_mutex_unlock(&scheduler->queue_mutex); /* if found task, do it, otherwise wait until other tasks are done */ if (found_task) { /* run task */ work_task->run(pool, work_task->taskdata, 0); /* delete task */ if (work_task->free_taskdata) MEM_freeN(work_task->taskdata); MEM_freeN(work_task); /* notify pool task was done */ task_pool_num_decrease(pool, 1); } BLI_mutex_lock(&pool->num_mutex); if (pool->num == 0) break; if (!found_task) BLI_condition_wait(&pool->num_cond, &pool->num_mutex); } BLI_mutex_unlock(&pool->num_mutex); }
static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task) { bool found_task = false; BLI_mutex_lock(&scheduler->queue_mutex); while (!scheduler->queue.first && !scheduler->do_exit) BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); do { Task *current_task; if (!scheduler->queue.first) { BLI_mutex_unlock(&scheduler->queue_mutex); BLI_assert(scheduler->do_exit); return false; } for (current_task = scheduler->queue.first; current_task != NULL; current_task = current_task->next) { TaskPool *pool = current_task->pool; if (pool->num_threads == 0 || pool->currently_running_tasks < pool->num_threads) { *task = current_task; found_task = true; atomic_add_z(&pool->currently_running_tasks, 1); BLI_remlink(&scheduler->queue, *task); break; } } if (!found_task) BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); } while (!found_task); BLI_mutex_unlock(&scheduler->queue_mutex); return true; }
void BLI_task_pool_cancel(TaskPool *pool) { pool->do_cancel = true; task_scheduler_clear(pool->scheduler, pool); /* wait until all entries are cleared */ BLI_mutex_lock(&pool->num_mutex); while (pool->num) BLI_condition_wait(&pool->num_cond, &pool->num_mutex); BLI_mutex_unlock(&pool->num_mutex); pool->do_cancel = false; }
static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task) { BLI_mutex_lock(&scheduler->queue_mutex); while (!scheduler->queue.first && !scheduler->do_exit) BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); if (!scheduler->queue.first) { BLI_mutex_unlock(&scheduler->queue_mutex); BLI_assert(scheduler->do_exit); return false; } *task = scheduler->queue.first; BLI_remlink(&scheduler->queue, *task); BLI_mutex_unlock(&scheduler->queue_mutex); return true; }