summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2016-06-11 17:51:22 +0200
committerMarek Olšák <[email protected]>2016-06-24 12:24:40 +0200
commit4358f6dd130680d60d48d6646959c11c8d7ca13d (patch)
tree9c9b63be1caf15bd655e9be749185d448c905923
parentd8367e91f2e3d8426e77674b39f36c09ed9992ec (diff)
gallium/u_queue: rewrite util_queue_fence to allow multiple waiters
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 <[email protected]>
-rw-r--r--src/gallium/auxiliary/util/u_queue.c49
-rw-r--r--src/gallium/auxiliary/util/u_queue.h10
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