static void task_free(TaskPool *pool, Task *task, const int thread_id) { task_data_free(task, thread_id); assert(thread_id >= 0); assert(thread_id <= pool->scheduler->num_threads); TaskMemPool *mem_pool = get_task_mempool(pool, thread_id); if (mem_pool->num_tasks < MEMPOOL_SIZE - 1) { /* Successfully allowed the task to be re-used later. */ mem_pool->tasks[mem_pool->num_tasks] = task; ++mem_pool->num_tasks; } else { /* Local storage saturated, no other way than just discard * the memory. * * TODO(sergey): We can perhaps store such pointer in a global * scheduler pool, maybe it'll be faster than discarding and * allocating again. */ MEM_freeN(task); #ifdef DEBUG_STATS pool->mempool_stats[thread_id].num_discard++; #endif } }
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 */ if (pool->num_threads == 0 || pool->currently_running_tasks < pool->num_threads) { 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 */ atomic_add_z(&pool->currently_running_tasks, 1); work_task->run(pool, work_task->taskdata, 0); /* delete task */ task_data_free(task, 0); 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); }
void BLI_task_scheduler_free(TaskScheduler *scheduler) { Task *task; /* stop all waiting threads */ BLI_mutex_lock(&scheduler->queue_mutex); scheduler->do_exit = true; BLI_condition_notify_all(&scheduler->queue_cond); BLI_mutex_unlock(&scheduler->queue_mutex); /* delete threads */ if (scheduler->threads) { int i; for (i = 0; i < scheduler->num_threads; i++) { if (pthread_join(scheduler->threads[i], NULL) != 0) fprintf(stderr, "TaskScheduler failed to join thread %d/%d\n", i, scheduler->num_threads); } MEM_freeN(scheduler->threads); } /* Delete task thread data */ if (scheduler->task_threads) { MEM_freeN(scheduler->task_threads); } /* Delete task memory pool */ if (scheduler->task_mempool) { for (int i = 0; i <= scheduler->num_threads; ++i) { for (int j = 0; j < scheduler->task_mempool[i].num_tasks; ++j) { MEM_freeN(scheduler->task_mempool[i].tasks[j]); } } MEM_freeN(scheduler->task_mempool); } /* delete leftover tasks */ for (task = scheduler->queue.first; task; task = task->next) { task_data_free(task, 0); } BLI_freelistN(&scheduler->queue); /* delete mutex/condition */ BLI_mutex_end(&scheduler->queue_mutex); BLI_condition_end(&scheduler->queue_cond); MEM_freeN(scheduler); }
static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool) { Task *task, *nexttask; size_t done = 0; BLI_mutex_lock(&scheduler->queue_mutex); /* free all tasks from this pool from the queue */ for (task = scheduler->queue.first; task; task = nexttask) { nexttask = task->next; if (task->pool == pool) { task_data_free(task, 0); BLI_freelinkN(&scheduler->queue, task); done++; } } BLI_mutex_unlock(&scheduler->queue_mutex); /* notify done */ task_pool_num_decrease(pool, done); }
static void *task_scheduler_thread_run(void *thread_p) { TaskThread *thread = (TaskThread *) thread_p; TaskScheduler *scheduler = thread->scheduler; int thread_id = thread->id; Task *task; /* keep popping off tasks */ while (task_scheduler_thread_wait_pop(scheduler, &task)) { TaskPool *pool = task->pool; /* run task */ task->run(pool, task->taskdata, thread_id); /* delete task */ task_data_free(task, thread_id); MEM_freeN(task); /* notify pool task was done */ task_pool_num_decrease(pool, 1); } return NULL; }