Esempio n. 1
0
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
	}
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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;
}