From: Marek Olšák <marek.ol...@amd.com> --- src/util/u_queue.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ src/util/u_queue.h | 2 ++ 2 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/src/util/u_queue.c b/src/util/u_queue.c index 8db09b0..3834b6f 100644 --- a/src/util/u_queue.c +++ b/src/util/u_queue.c @@ -173,27 +173,29 @@ util_queue_thread_func(void *input) if (job.job) { job.execute(job.job, thread_index); util_queue_fence_signal(job.fence); if (job.cleanup) job.cleanup(job.job, thread_index); } } /* signal remaining jobs before terminating */ mtx_lock(&queue->lock); - while (queue->jobs[queue->read_idx].job) { - util_queue_fence_signal(queue->jobs[queue->read_idx].fence); - - queue->jobs[queue->read_idx].job = NULL; - queue->read_idx = (queue->read_idx + 1) % queue->max_jobs; + for (unsigned i = queue->read_idx; i != queue->write_idx; + i = (i + 1) % queue->max_jobs) { + if (queue->jobs[i].job) { + util_queue_fence_signal(queue->jobs[i].fence); + queue->jobs[i].job = NULL; + } } - queue->num_queued = 0; /* reset this when exiting the thread */ + queue->read_idx = (queue->read_idx + queue->num_queued) % queue->max_jobs; + queue->num_queued = 0; mtx_unlock(&queue->lock); return 0; } bool util_queue_init(struct util_queue *queue, const char *name, unsigned max_jobs, unsigned num_threads) { @@ -322,19 +324,55 @@ util_queue_add_job(struct util_queue *queue, ptr->fence = fence; ptr->execute = execute; ptr->cleanup = cleanup; queue->write_idx = (queue->write_idx + 1) % queue->max_jobs; queue->num_queued++; cnd_signal(&queue->has_queued_cond); mtx_unlock(&queue->lock); } +/** + * Remove a queued job. If the job hasn't started execution, it's removed from + * the queue. If the job has started execution, the function waits for it to + * complete. + * + * In all cases, the fence is signalled when the function returns. + * + * The function can be used when destroying an object associated with the job + * when you don't care about the job completion state. + */ +void +util_queue_drop_job(struct util_queue *queue, struct util_queue_fence *fence) +{ + bool removed = false; + + if (util_queue_fence_is_signalled(fence)) + return; + + mtx_lock(&queue->lock); + for (unsigned i = queue->read_idx; i != queue->write_idx; + i = (i + 1) % queue->max_jobs) { + if (queue->jobs[i].fence == fence) { + /* Just clear it. The threads will drop it. */ + memset(&queue->jobs[i], 0, sizeof(queue->jobs[i])); + removed = true; + break; + } + } + mtx_unlock(&queue->lock); + + if (removed) + util_queue_fence_signal(fence); + else + util_queue_fence_wait(fence); +} + int64_t util_queue_get_thread_time_nano(struct util_queue *queue, unsigned thread_index) { /* Allow some flexibility by not raising an error. */ if (thread_index >= queue->num_threads) return 0; return u_thread_get_time_nano(queue->threads[thread_index]); } diff --git a/src/util/u_queue.h b/src/util/u_queue.h index 4aec1f2..9876865 100644 --- a/src/util/u_queue.h +++ b/src/util/u_queue.h @@ -85,20 +85,22 @@ bool util_queue_init(struct util_queue *queue, void util_queue_destroy(struct util_queue *queue); void util_queue_fence_init(struct util_queue_fence *fence); void util_queue_fence_destroy(struct util_queue_fence *fence); /* optional cleanup callback is called after fence is signaled: */ void util_queue_add_job(struct util_queue *queue, void *job, struct util_queue_fence *fence, util_queue_execute_func execute, util_queue_execute_func cleanup); +void util_queue_drop_job(struct util_queue *queue, + struct util_queue_fence *fence); void util_queue_fence_wait(struct util_queue_fence *fence); int64_t util_queue_get_thread_time_nano(struct util_queue *queue, unsigned thread_index); /* util_queue needs to be cleared to zeroes for this to work */ static inline bool util_queue_is_initialized(struct util_queue *queue) { return queue->threads != NULL; -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev