From 33e507ec23db3778294b75a1485021d2a35b0a22 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Wed, 31 May 2017 16:44:12 +0200 Subject: [PATCH] util/u_queue: add a way to remove a job when we just want to destroy it MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reviewed-by: Nicolai Hähnle --- src/util/u_queue.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ src/util/u_queue.h | 2 ++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/util/u_queue.c b/src/util/u_queue.c index 8db09b0..01c3a96 100644 --- a/src/util/u_queue.c +++ b/src/util/u_queue.c @@ -180,13 +180,15 @@ util_queue_thread_func(void *input) /* 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->write_idx; + queue->num_queued = 0; mtx_unlock(&queue->lock); return 0; } @@ -329,6 +331,45 @@ util_queue_add_job(struct util_queue *queue, 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) { + if (queue->jobs[i].cleanup) + queue->jobs[i].cleanup(queue->jobs[i].job, -1); + + /* Just clear it. The threads will treat as a no-op job. */ + 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) { 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 @@ -92,6 +92,8 @@ void util_queue_add_job(struct util_queue *queue, 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, -- 2.7.4