summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary/util/u_queue.c
blob: 8e58414247b3367bb27afda4f790552b281cde4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright © 2016 Advanced Micro Devices, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 */

#include "u_queue.h"

static PIPE_THREAD_ROUTINE(util_queue_thread_func, param)
{
   struct util_queue *queue = (struct util_queue*)param;
   unsigned i;

   while (1) {
      struct util_queue_job job;

      pipe_semaphore_wait(&queue->queued);
      if (queue->kill_thread)
         break;

      pipe_mutex_lock(queue->lock);
      job = queue->jobs[0];
      for (i = 1; i < queue->num_jobs; i++)
         queue->jobs[i - 1] = queue->jobs[i];
      queue->jobs[--queue->num_jobs].job = NULL;
      pipe_mutex_unlock(queue->lock);

      pipe_semaphore_signal(&queue->has_space);

      if (job.job) {
         queue->execute_job(job.job);
         pipe_semaphore_signal(&job.fence->done);
      }
   }

   /* signal remaining jobs before terminating */
   pipe_mutex_lock(queue->lock);
   for (i = 0; i < queue->num_jobs; i++) {
      pipe_semaphore_signal(&queue->jobs[i].fence->done);
      queue->jobs[i].job = NULL;
   }
   queue->num_jobs = 0;
   pipe_mutex_unlock(queue->lock);
   return 0;
}

void
util_queue_init(struct util_queue *queue,
                void (*execute_job)(void *))
{
   memset(queue, 0, sizeof(*queue));
   queue->execute_job = execute_job;
   pipe_mutex_init(queue->lock);
   pipe_semaphore_init(&queue->has_space, ARRAY_SIZE(queue->jobs));
   pipe_semaphore_init(&queue->queued, 0);
   queue->thread = pipe_thread_create(util_queue_thread_func, queue);
}

void
util_queue_destroy(struct util_queue *queue)
{
   queue->kill_thread = 1;
   pipe_semaphore_signal(&queue->queued);
   pipe_thread_wait(queue->thread);
   pipe_semaphore_destroy(&queue->has_space);
   pipe_semaphore_destroy(&queue->queued);
   pipe_mutex_destroy(queue->lock);
}

void
util_queue_fence_init(struct util_queue_fence *fence)
{
   pipe_semaphore_init(&fence->done, 1);
}

void
util_queue_fence_destroy(struct util_queue_fence *fence)
{
   pipe_semaphore_destroy(&fence->done);
}

void
util_queue_add_job(struct util_queue *queue,
                   void *job,
                   struct util_queue_fence *fence)
{
   /* Set the semaphore to "busy". */
   pipe_semaphore_wait(&fence->done);

   /* if the queue is full, wait until there is space */
   pipe_semaphore_wait(&queue->has_space);

   pipe_mutex_lock(queue->lock);
   assert(queue->num_jobs < ARRAY_SIZE(queue->jobs));
   queue->jobs[queue->num_jobs].job = job;
   queue->jobs[queue->num_jobs].fence = fence;
   queue->num_jobs++;
   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);
}