From 4358f6dd130680d60d48d6646959c11c8d7ca13d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sat, 11 Jun 2016 17:51:22 +0200 Subject: [PATCH] gallium/u_queue: rewrite util_queue_fence to allow multiple waiters MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Checking "signalled" is first done without a mutex, then with a mutex. Also, checking without waiting doesn't lock the mutex. This is racy, but should be safe. Reviewed-by: Nicolai Hähnle --- src/gallium/auxiliary/util/u_queue.c | 49 +++++++++++++++++++--------- src/gallium/auxiliary/util/u_queue.h | 10 +++++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/gallium/auxiliary/util/u_queue.c b/src/gallium/auxiliary/util/u_queue.c index 2b6850d02e4..7a67c1169d9 100644 --- a/src/gallium/auxiliary/util/u_queue.c +++ b/src/gallium/auxiliary/util/u_queue.c @@ -25,6 +25,28 @@ */ #include "u_queue.h" +#include "os/os_time.h" + +static void +util_queue_fence_signal(struct util_queue_fence *fence) +{ + pipe_mutex_lock(fence->mutex); + fence->signalled = true; + pipe_condvar_broadcast(fence->cond); + pipe_mutex_unlock(fence->mutex); +} + +void +util_queue_job_wait(struct util_queue_fence *fence) +{ + if (fence->signalled) + return; + + pipe_mutex_lock(fence->mutex); + while (!fence->signalled) + pipe_condvar_wait(fence->cond, fence->mutex); + pipe_mutex_unlock(fence->mutex); +} static PIPE_THREAD_ROUTINE(util_queue_thread_func, param) { @@ -47,14 +69,15 @@ static PIPE_THREAD_ROUTINE(util_queue_thread_func, param) if (job.job) { queue->execute_job(job.job); - pipe_semaphore_signal(&job.fence->done); + util_queue_fence_signal(job.fence); } } /* signal remaining jobs before terminating */ pipe_mutex_lock(queue->lock); while (queue->jobs[queue->read_idx].job) { - pipe_semaphore_signal(&queue->jobs[queue->read_idx].fence->done); + 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; } @@ -113,13 +136,17 @@ util_queue_destroy(struct util_queue *queue) void util_queue_fence_init(struct util_queue_fence *fence) { - pipe_semaphore_init(&fence->done, 1); + memset(fence, 0, sizeof(*fence)); + pipe_mutex_init(fence->mutex); + pipe_condvar_init(fence->cond); + fence->signalled = true; } void util_queue_fence_destroy(struct util_queue_fence *fence) { - pipe_semaphore_destroy(&fence->done); + pipe_condvar_destroy(fence->cond); + pipe_mutex_destroy(fence->mutex); } void @@ -128,8 +155,9 @@ util_queue_add_job(struct util_queue *queue, struct util_queue_fence *fence) { struct util_queue_job *ptr; - /* Set the semaphore to "busy". */ - pipe_semaphore_wait(&fence->done); + + assert(fence->signalled); + fence->signalled = false; /* if the queue is full, wait until there is space */ pipe_semaphore_wait(&queue->has_space); @@ -143,12 +171,3 @@ util_queue_add_job(struct util_queue *queue, pipe_mutex_unlock(queue->lock); pipe_semaphore_signal(&queue->queued); } - -void -util_queue_job_wait(struct util_queue_fence *fence) -{ - /* wait and set the semaphore to "busy" */ - pipe_semaphore_wait(&fence->done); - /* set the semaphore to "idle" */ - pipe_semaphore_signal(&fence->done); -} diff --git a/src/gallium/auxiliary/util/u_queue.h b/src/gallium/auxiliary/util/u_queue.h index 48cd9f4c707..acebb51382f 100644 --- a/src/gallium/auxiliary/util/u_queue.h +++ b/src/gallium/auxiliary/util/u_queue.h @@ -39,7 +39,9 @@ * Put this into your job structure. */ struct util_queue_fence { - pipe_semaphore done; + pipe_mutex mutex; + pipe_condvar cond; + int signalled; }; struct util_queue_job { @@ -79,4 +81,10 @@ util_queue_is_initialized(struct util_queue *queue) return queue->thread != 0; } +static inline bool +util_queue_fence_is_signalled(struct util_queue_fence *fence) +{ + return fence->signalled != 0; +} + #endif -- 2.30.2