util: hashtable: make hashing prototypes match
[mesa.git] / src / util / u_queue.c
index 01c3a96d5f3709afd6056bad481175788fe6e8a2..3b05110e9f8aa548d301cbf560f0b9477361168d 100644 (file)
@@ -120,6 +120,19 @@ void
 util_queue_fence_destroy(struct util_queue_fence *fence)
 {
    assert(fence->signalled);
+
+   /* Ensure that another thread is not in the middle of
+    * util_queue_fence_signal (having set the fence to signalled but still
+    * holding the fence mutex).
+    *
+    * A common contract between threads is that as soon as a fence is signalled
+    * by thread A, thread B is allowed to destroy it. Since
+    * util_queue_fence_is_signalled does not lock the fence mutex (for
+    * performance reasons), we must do so here.
+    */
+   mtx_lock(&fence->mutex);
+   mtx_unlock(&fence->mutex);
+
    cnd_destroy(&fence->cond);
    mtx_destroy(&fence->mutex);
 }
@@ -197,12 +210,14 @@ bool
 util_queue_init(struct util_queue *queue,
                 const char *name,
                 unsigned max_jobs,
-                unsigned num_threads)
+                unsigned num_threads,
+                unsigned flags)
 {
    unsigned i;
 
    memset(queue, 0, sizeof(*queue));
    queue->name = name;
+   queue->flags = flags;
    queue->num_threads = num_threads;
    queue->max_jobs = max_jobs;
 
@@ -242,6 +257,20 @@ util_queue_init(struct util_queue *queue,
             break;
          }
       }
+
+      if (flags & UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY) {
+   #if defined(__linux__) && defined(SCHED_IDLE)
+         struct sched_param sched_param = {0};
+
+         /* The nice() function can only set a maximum of 19.
+          * SCHED_IDLE is the same as nice = 20.
+          *
+          * Note that Linux only allows decreasing the priority. The original
+          * priority can't be restored.
+          */
+         pthread_setschedparam(queue->threads[i], SCHED_IDLE, &sched_param);
+   #endif
+      }
    }
 
    add_to_atexit_list(queue);
@@ -314,9 +343,39 @@ util_queue_add_job(struct util_queue *queue,
 
    assert(queue->num_queued >= 0 && queue->num_queued <= queue->max_jobs);
 
-   /* if the queue is full, wait until there is space */
-   while (queue->num_queued == queue->max_jobs)
-      cnd_wait(&queue->has_space_cond, &queue->lock);
+   if (queue->num_queued == queue->max_jobs) {
+      if (queue->flags & UTIL_QUEUE_INIT_RESIZE_IF_FULL) {
+         /* If the queue is full, make it larger to avoid waiting for a free
+          * slot.
+          */
+         unsigned new_max_jobs = queue->max_jobs + 8;
+         struct util_queue_job *jobs =
+            (struct util_queue_job*)calloc(new_max_jobs,
+                                           sizeof(struct util_queue_job));
+         assert(jobs);
+
+         /* Copy all queued jobs into the new list. */
+         unsigned num_jobs = 0;
+         unsigned i = queue->read_idx;
+
+         do {
+            jobs[num_jobs++] = queue->jobs[i];
+            i = (i + 1) % queue->max_jobs;
+         } while (i != queue->write_idx);
+
+         assert(num_jobs == queue->num_queued);
+
+         free(queue->jobs);
+         queue->jobs = jobs;
+         queue->read_idx = 0;
+         queue->write_idx = num_jobs;
+         queue->max_jobs = new_max_jobs;
+      } else {
+         /* Wait until there is a free slot. */
+         while (queue->num_queued == queue->max_jobs)
+            cnd_wait(&queue->has_space_cond, &queue->lock);
+      }
+   }
 
    ptr = &queue->jobs[queue->write_idx];
    assert(ptr->job == NULL);