1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2016 Advanced Micro Devices, Inc.
3*61046927SAndroid Build Coastguard Worker * All Rights Reserved.
4*61046927SAndroid Build Coastguard Worker *
5*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining
6*61046927SAndroid Build Coastguard Worker * a copy of this software and associated documentation files (the
7*61046927SAndroid Build Coastguard Worker * "Software"), to deal in the Software without restriction, including
8*61046927SAndroid Build Coastguard Worker * without limitation the rights to use, copy, modify, merge, publish,
9*61046927SAndroid Build Coastguard Worker * distribute, sub license, and/or sell copies of the Software, and to
10*61046927SAndroid Build Coastguard Worker * permit persons to whom the Software is furnished to do so, subject to
11*61046927SAndroid Build Coastguard Worker * the following conditions:
12*61046927SAndroid Build Coastguard Worker *
13*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14*61046927SAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15*61046927SAndroid Build Coastguard Worker * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16*61046927SAndroid Build Coastguard Worker * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17*61046927SAndroid Build Coastguard Worker * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*61046927SAndroid Build Coastguard Worker * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20*61046927SAndroid Build Coastguard Worker * USE OR OTHER DEALINGS IN THE SOFTWARE.
21*61046927SAndroid Build Coastguard Worker *
22*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the
23*61046927SAndroid Build Coastguard Worker * next paragraph) shall be included in all copies or substantial portions
24*61046927SAndroid Build Coastguard Worker * of the Software.
25*61046927SAndroid Build Coastguard Worker */
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "u_queue.h"
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker #include "c11/threads.h"
30*61046927SAndroid Build Coastguard Worker #include "util/u_cpu_detect.h"
31*61046927SAndroid Build Coastguard Worker #include "util/os_time.h"
32*61046927SAndroid Build Coastguard Worker #include "util/u_string.h"
33*61046927SAndroid Build Coastguard Worker #include "util/u_thread.h"
34*61046927SAndroid Build Coastguard Worker #include "util/timespec.h"
35*61046927SAndroid Build Coastguard Worker #include "u_process.h"
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker #if defined(__linux__)
38*61046927SAndroid Build Coastguard Worker #include <sys/time.h>
39*61046927SAndroid Build Coastguard Worker #include <sys/resource.h>
40*61046927SAndroid Build Coastguard Worker #include <sys/syscall.h>
41*61046927SAndroid Build Coastguard Worker #endif
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker /* Define 256MB */
45*61046927SAndroid Build Coastguard Worker #define S_256MB (256 * 1024 * 1024)
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker static void
48*61046927SAndroid Build Coastguard Worker util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads,
49*61046927SAndroid Build Coastguard Worker bool locked);
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker /****************************************************************************
52*61046927SAndroid Build Coastguard Worker * Wait for all queues to assert idle when exit() is called.
53*61046927SAndroid Build Coastguard Worker *
54*61046927SAndroid Build Coastguard Worker * Otherwise, C++ static variable destructors can be called while threads
55*61046927SAndroid Build Coastguard Worker * are using the static variables.
56*61046927SAndroid Build Coastguard Worker */
57*61046927SAndroid Build Coastguard Worker
58*61046927SAndroid Build Coastguard Worker static once_flag atexit_once_flag = ONCE_FLAG_INIT;
59*61046927SAndroid Build Coastguard Worker static struct list_head queue_list = {
60*61046927SAndroid Build Coastguard Worker .next = &queue_list,
61*61046927SAndroid Build Coastguard Worker .prev = &queue_list,
62*61046927SAndroid Build Coastguard Worker };
63*61046927SAndroid Build Coastguard Worker static mtx_t exit_mutex;
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker static void
atexit_handler(void)66*61046927SAndroid Build Coastguard Worker atexit_handler(void)
67*61046927SAndroid Build Coastguard Worker {
68*61046927SAndroid Build Coastguard Worker struct util_queue *iter;
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Worker mtx_lock(&exit_mutex);
71*61046927SAndroid Build Coastguard Worker /* Wait for all queues to assert idle. */
72*61046927SAndroid Build Coastguard Worker LIST_FOR_EACH_ENTRY(iter, &queue_list, head) {
73*61046927SAndroid Build Coastguard Worker util_queue_kill_threads(iter, 0, false);
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker mtx_unlock(&exit_mutex);
76*61046927SAndroid Build Coastguard Worker }
77*61046927SAndroid Build Coastguard Worker
78*61046927SAndroid Build Coastguard Worker static void
global_init(void)79*61046927SAndroid Build Coastguard Worker global_init(void)
80*61046927SAndroid Build Coastguard Worker {
81*61046927SAndroid Build Coastguard Worker mtx_init(&exit_mutex, mtx_plain);
82*61046927SAndroid Build Coastguard Worker atexit(atexit_handler);
83*61046927SAndroid Build Coastguard Worker }
84*61046927SAndroid Build Coastguard Worker
85*61046927SAndroid Build Coastguard Worker static void
add_to_atexit_list(struct util_queue * queue)86*61046927SAndroid Build Coastguard Worker add_to_atexit_list(struct util_queue *queue)
87*61046927SAndroid Build Coastguard Worker {
88*61046927SAndroid Build Coastguard Worker call_once(&atexit_once_flag, global_init);
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker mtx_lock(&exit_mutex);
91*61046927SAndroid Build Coastguard Worker list_add(&queue->head, &queue_list);
92*61046927SAndroid Build Coastguard Worker mtx_unlock(&exit_mutex);
93*61046927SAndroid Build Coastguard Worker }
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker static void
remove_from_atexit_list(struct util_queue * queue)96*61046927SAndroid Build Coastguard Worker remove_from_atexit_list(struct util_queue *queue)
97*61046927SAndroid Build Coastguard Worker {
98*61046927SAndroid Build Coastguard Worker struct util_queue *iter, *tmp;
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker mtx_lock(&exit_mutex);
101*61046927SAndroid Build Coastguard Worker LIST_FOR_EACH_ENTRY_SAFE(iter, tmp, &queue_list, head) {
102*61046927SAndroid Build Coastguard Worker if (iter == queue) {
103*61046927SAndroid Build Coastguard Worker list_del(&iter->head);
104*61046927SAndroid Build Coastguard Worker break;
105*61046927SAndroid Build Coastguard Worker }
106*61046927SAndroid Build Coastguard Worker }
107*61046927SAndroid Build Coastguard Worker mtx_unlock(&exit_mutex);
108*61046927SAndroid Build Coastguard Worker }
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker /****************************************************************************
111*61046927SAndroid Build Coastguard Worker * util_queue_fence
112*61046927SAndroid Build Coastguard Worker */
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker #ifdef UTIL_QUEUE_FENCE_FUTEX
115*61046927SAndroid Build Coastguard Worker static bool
do_futex_fence_wait(struct util_queue_fence * fence,bool timeout,int64_t abs_timeout)116*61046927SAndroid Build Coastguard Worker do_futex_fence_wait(struct util_queue_fence *fence,
117*61046927SAndroid Build Coastguard Worker bool timeout, int64_t abs_timeout)
118*61046927SAndroid Build Coastguard Worker {
119*61046927SAndroid Build Coastguard Worker uint32_t v = p_atomic_read_relaxed(&fence->val);
120*61046927SAndroid Build Coastguard Worker struct timespec ts;
121*61046927SAndroid Build Coastguard Worker ts.tv_sec = abs_timeout / (1000*1000*1000);
122*61046927SAndroid Build Coastguard Worker ts.tv_nsec = abs_timeout % (1000*1000*1000);
123*61046927SAndroid Build Coastguard Worker
124*61046927SAndroid Build Coastguard Worker while (v != 0) {
125*61046927SAndroid Build Coastguard Worker if (v != 2) {
126*61046927SAndroid Build Coastguard Worker v = p_atomic_cmpxchg(&fence->val, 1, 2);
127*61046927SAndroid Build Coastguard Worker if (v == 0)
128*61046927SAndroid Build Coastguard Worker return true;
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker int r = futex_wait(&fence->val, 2, timeout ? &ts : NULL);
132*61046927SAndroid Build Coastguard Worker if (timeout && r < 0) {
133*61046927SAndroid Build Coastguard Worker if (errno == ETIMEDOUT)
134*61046927SAndroid Build Coastguard Worker return false;
135*61046927SAndroid Build Coastguard Worker }
136*61046927SAndroid Build Coastguard Worker
137*61046927SAndroid Build Coastguard Worker v = p_atomic_read_relaxed(&fence->val);
138*61046927SAndroid Build Coastguard Worker }
139*61046927SAndroid Build Coastguard Worker
140*61046927SAndroid Build Coastguard Worker return true;
141*61046927SAndroid Build Coastguard Worker }
142*61046927SAndroid Build Coastguard Worker
143*61046927SAndroid Build Coastguard Worker void
_util_queue_fence_wait(struct util_queue_fence * fence)144*61046927SAndroid Build Coastguard Worker _util_queue_fence_wait(struct util_queue_fence *fence)
145*61046927SAndroid Build Coastguard Worker {
146*61046927SAndroid Build Coastguard Worker do_futex_fence_wait(fence, false, 0);
147*61046927SAndroid Build Coastguard Worker }
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker bool
_util_queue_fence_wait_timeout(struct util_queue_fence * fence,int64_t abs_timeout)150*61046927SAndroid Build Coastguard Worker _util_queue_fence_wait_timeout(struct util_queue_fence *fence,
151*61046927SAndroid Build Coastguard Worker int64_t abs_timeout)
152*61046927SAndroid Build Coastguard Worker {
153*61046927SAndroid Build Coastguard Worker return do_futex_fence_wait(fence, true, abs_timeout);
154*61046927SAndroid Build Coastguard Worker }
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker #endif
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker #ifdef UTIL_QUEUE_FENCE_STANDARD
159*61046927SAndroid Build Coastguard Worker void
util_queue_fence_signal(struct util_queue_fence * fence)160*61046927SAndroid Build Coastguard Worker util_queue_fence_signal(struct util_queue_fence *fence)
161*61046927SAndroid Build Coastguard Worker {
162*61046927SAndroid Build Coastguard Worker mtx_lock(&fence->mutex);
163*61046927SAndroid Build Coastguard Worker fence->signalled = true;
164*61046927SAndroid Build Coastguard Worker u_cnd_monotonic_broadcast(&fence->cond);
165*61046927SAndroid Build Coastguard Worker mtx_unlock(&fence->mutex);
166*61046927SAndroid Build Coastguard Worker }
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Worker void
_util_queue_fence_wait(struct util_queue_fence * fence)169*61046927SAndroid Build Coastguard Worker _util_queue_fence_wait(struct util_queue_fence *fence)
170*61046927SAndroid Build Coastguard Worker {
171*61046927SAndroid Build Coastguard Worker mtx_lock(&fence->mutex);
172*61046927SAndroid Build Coastguard Worker while (!fence->signalled)
173*61046927SAndroid Build Coastguard Worker u_cnd_monotonic_wait(&fence->cond, &fence->mutex);
174*61046927SAndroid Build Coastguard Worker mtx_unlock(&fence->mutex);
175*61046927SAndroid Build Coastguard Worker }
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker bool
_util_queue_fence_wait_timeout(struct util_queue_fence * fence,int64_t abs_timeout)178*61046927SAndroid Build Coastguard Worker _util_queue_fence_wait_timeout(struct util_queue_fence *fence,
179*61046927SAndroid Build Coastguard Worker int64_t abs_timeout)
180*61046927SAndroid Build Coastguard Worker {
181*61046927SAndroid Build Coastguard Worker struct timespec ts;
182*61046927SAndroid Build Coastguard Worker timespec_from_nsec(&ts, abs_timeout);
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Worker mtx_lock(&fence->mutex);
185*61046927SAndroid Build Coastguard Worker while (!fence->signalled) {
186*61046927SAndroid Build Coastguard Worker if (u_cnd_monotonic_timedwait(&fence->cond, &fence->mutex, &ts) != thrd_success)
187*61046927SAndroid Build Coastguard Worker break;
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker mtx_unlock(&fence->mutex);
190*61046927SAndroid Build Coastguard Worker
191*61046927SAndroid Build Coastguard Worker return fence->signalled;
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker void
util_queue_fence_init(struct util_queue_fence * fence)195*61046927SAndroid Build Coastguard Worker util_queue_fence_init(struct util_queue_fence *fence)
196*61046927SAndroid Build Coastguard Worker {
197*61046927SAndroid Build Coastguard Worker memset(fence, 0, sizeof(*fence));
198*61046927SAndroid Build Coastguard Worker (void) mtx_init(&fence->mutex, mtx_plain);
199*61046927SAndroid Build Coastguard Worker u_cnd_monotonic_init(&fence->cond);
200*61046927SAndroid Build Coastguard Worker fence->signalled = true;
201*61046927SAndroid Build Coastguard Worker }
202*61046927SAndroid Build Coastguard Worker
203*61046927SAndroid Build Coastguard Worker void
util_queue_fence_destroy(struct util_queue_fence * fence)204*61046927SAndroid Build Coastguard Worker util_queue_fence_destroy(struct util_queue_fence *fence)
205*61046927SAndroid Build Coastguard Worker {
206*61046927SAndroid Build Coastguard Worker assert(fence->signalled);
207*61046927SAndroid Build Coastguard Worker
208*61046927SAndroid Build Coastguard Worker /* Ensure that another thread is not in the middle of
209*61046927SAndroid Build Coastguard Worker * util_queue_fence_signal (having set the fence to signalled but still
210*61046927SAndroid Build Coastguard Worker * holding the fence mutex).
211*61046927SAndroid Build Coastguard Worker *
212*61046927SAndroid Build Coastguard Worker * A common contract between threads is that as soon as a fence is signalled
213*61046927SAndroid Build Coastguard Worker * by thread A, thread B is allowed to destroy it. Since
214*61046927SAndroid Build Coastguard Worker * util_queue_fence_is_signalled does not lock the fence mutex (for
215*61046927SAndroid Build Coastguard Worker * performance reasons), we must do so here.
216*61046927SAndroid Build Coastguard Worker */
217*61046927SAndroid Build Coastguard Worker mtx_lock(&fence->mutex);
218*61046927SAndroid Build Coastguard Worker mtx_unlock(&fence->mutex);
219*61046927SAndroid Build Coastguard Worker
220*61046927SAndroid Build Coastguard Worker u_cnd_monotonic_destroy(&fence->cond);
221*61046927SAndroid Build Coastguard Worker mtx_destroy(&fence->mutex);
222*61046927SAndroid Build Coastguard Worker }
223*61046927SAndroid Build Coastguard Worker #endif
224*61046927SAndroid Build Coastguard Worker
225*61046927SAndroid Build Coastguard Worker /****************************************************************************
226*61046927SAndroid Build Coastguard Worker * util_queue implementation
227*61046927SAndroid Build Coastguard Worker */
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker struct thread_input {
230*61046927SAndroid Build Coastguard Worker struct util_queue *queue;
231*61046927SAndroid Build Coastguard Worker int thread_index;
232*61046927SAndroid Build Coastguard Worker };
233*61046927SAndroid Build Coastguard Worker
234*61046927SAndroid Build Coastguard Worker static int
util_queue_thread_func(void * input)235*61046927SAndroid Build Coastguard Worker util_queue_thread_func(void *input)
236*61046927SAndroid Build Coastguard Worker {
237*61046927SAndroid Build Coastguard Worker struct util_queue *queue = ((struct thread_input*)input)->queue;
238*61046927SAndroid Build Coastguard Worker int thread_index = ((struct thread_input*)input)->thread_index;
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker free(input);
241*61046927SAndroid Build Coastguard Worker
242*61046927SAndroid Build Coastguard Worker if (queue->flags & UTIL_QUEUE_INIT_SET_FULL_THREAD_AFFINITY) {
243*61046927SAndroid Build Coastguard Worker /* Don't inherit the thread affinity from the parent thread.
244*61046927SAndroid Build Coastguard Worker * Set the full mask.
245*61046927SAndroid Build Coastguard Worker */
246*61046927SAndroid Build Coastguard Worker uint32_t mask[UTIL_MAX_CPUS / 32];
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker memset(mask, 0xff, sizeof(mask));
249*61046927SAndroid Build Coastguard Worker
250*61046927SAndroid Build Coastguard Worker util_set_current_thread_affinity(mask, NULL,
251*61046927SAndroid Build Coastguard Worker util_get_cpu_caps()->num_cpu_mask_bits);
252*61046927SAndroid Build Coastguard Worker }
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker #if defined(__linux__)
255*61046927SAndroid Build Coastguard Worker if (queue->flags & UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY) {
256*61046927SAndroid Build Coastguard Worker /* The nice() function can only set a maximum of 19. */
257*61046927SAndroid Build Coastguard Worker setpriority(PRIO_PROCESS, syscall(SYS_gettid), 19);
258*61046927SAndroid Build Coastguard Worker }
259*61046927SAndroid Build Coastguard Worker #endif
260*61046927SAndroid Build Coastguard Worker
261*61046927SAndroid Build Coastguard Worker if (strlen(queue->name) > 0) {
262*61046927SAndroid Build Coastguard Worker char name[16];
263*61046927SAndroid Build Coastguard Worker snprintf(name, sizeof(name), "%s%i", queue->name, thread_index);
264*61046927SAndroid Build Coastguard Worker u_thread_setname(name);
265*61046927SAndroid Build Coastguard Worker }
266*61046927SAndroid Build Coastguard Worker
267*61046927SAndroid Build Coastguard Worker while (1) {
268*61046927SAndroid Build Coastguard Worker struct util_queue_job job;
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
271*61046927SAndroid Build Coastguard Worker assert(queue->num_queued >= 0 && queue->num_queued <= queue->max_jobs);
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker /* wait if the queue is empty */
274*61046927SAndroid Build Coastguard Worker while (thread_index < queue->num_threads && queue->num_queued == 0)
275*61046927SAndroid Build Coastguard Worker cnd_wait(&queue->has_queued_cond, &queue->lock);
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker /* only kill threads that are above "num_threads" */
278*61046927SAndroid Build Coastguard Worker if (thread_index >= queue->num_threads) {
279*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
280*61046927SAndroid Build Coastguard Worker break;
281*61046927SAndroid Build Coastguard Worker }
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker job = queue->jobs[queue->read_idx];
284*61046927SAndroid Build Coastguard Worker memset(&queue->jobs[queue->read_idx], 0, sizeof(struct util_queue_job));
285*61046927SAndroid Build Coastguard Worker queue->read_idx = (queue->read_idx + 1) % queue->max_jobs;
286*61046927SAndroid Build Coastguard Worker
287*61046927SAndroid Build Coastguard Worker queue->num_queued--;
288*61046927SAndroid Build Coastguard Worker cnd_signal(&queue->has_space_cond);
289*61046927SAndroid Build Coastguard Worker if (job.job)
290*61046927SAndroid Build Coastguard Worker queue->total_jobs_size -= job.job_size;
291*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
292*61046927SAndroid Build Coastguard Worker
293*61046927SAndroid Build Coastguard Worker if (job.job) {
294*61046927SAndroid Build Coastguard Worker job.execute(job.job, job.global_data, thread_index);
295*61046927SAndroid Build Coastguard Worker if (job.fence)
296*61046927SAndroid Build Coastguard Worker util_queue_fence_signal(job.fence);
297*61046927SAndroid Build Coastguard Worker if (job.cleanup)
298*61046927SAndroid Build Coastguard Worker job.cleanup(job.job, job.global_data, thread_index);
299*61046927SAndroid Build Coastguard Worker }
300*61046927SAndroid Build Coastguard Worker }
301*61046927SAndroid Build Coastguard Worker
302*61046927SAndroid Build Coastguard Worker /* signal remaining jobs if all threads are being terminated */
303*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
304*61046927SAndroid Build Coastguard Worker if (queue->num_threads == 0) {
305*61046927SAndroid Build Coastguard Worker for (unsigned i = queue->read_idx; i != queue->write_idx;
306*61046927SAndroid Build Coastguard Worker i = (i + 1) % queue->max_jobs) {
307*61046927SAndroid Build Coastguard Worker if (queue->jobs[i].job) {
308*61046927SAndroid Build Coastguard Worker if (queue->jobs[i].fence)
309*61046927SAndroid Build Coastguard Worker util_queue_fence_signal(queue->jobs[i].fence);
310*61046927SAndroid Build Coastguard Worker queue->jobs[i].job = NULL;
311*61046927SAndroid Build Coastguard Worker }
312*61046927SAndroid Build Coastguard Worker }
313*61046927SAndroid Build Coastguard Worker queue->read_idx = queue->write_idx;
314*61046927SAndroid Build Coastguard Worker queue->num_queued = 0;
315*61046927SAndroid Build Coastguard Worker }
316*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
317*61046927SAndroid Build Coastguard Worker return 0;
318*61046927SAndroid Build Coastguard Worker }
319*61046927SAndroid Build Coastguard Worker
320*61046927SAndroid Build Coastguard Worker static bool
util_queue_create_thread(struct util_queue * queue,unsigned index)321*61046927SAndroid Build Coastguard Worker util_queue_create_thread(struct util_queue *queue, unsigned index)
322*61046927SAndroid Build Coastguard Worker {
323*61046927SAndroid Build Coastguard Worker struct thread_input *input =
324*61046927SAndroid Build Coastguard Worker (struct thread_input *) malloc(sizeof(struct thread_input));
325*61046927SAndroid Build Coastguard Worker input->queue = queue;
326*61046927SAndroid Build Coastguard Worker input->thread_index = index;
327*61046927SAndroid Build Coastguard Worker
328*61046927SAndroid Build Coastguard Worker if (thrd_success != u_thread_create(queue->threads + index, util_queue_thread_func, input)) {
329*61046927SAndroid Build Coastguard Worker free(input);
330*61046927SAndroid Build Coastguard Worker return false;
331*61046927SAndroid Build Coastguard Worker }
332*61046927SAndroid Build Coastguard Worker
333*61046927SAndroid Build Coastguard Worker if (queue->flags & UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY) {
334*61046927SAndroid Build Coastguard Worker #if defined(__linux__) && defined(SCHED_BATCH)
335*61046927SAndroid Build Coastguard Worker struct sched_param sched_param = {0};
336*61046927SAndroid Build Coastguard Worker
337*61046927SAndroid Build Coastguard Worker /* The nice() function can only set a maximum of 19.
338*61046927SAndroid Build Coastguard Worker * SCHED_BATCH gives the scheduler a hint that this is a latency
339*61046927SAndroid Build Coastguard Worker * insensitive thread.
340*61046927SAndroid Build Coastguard Worker *
341*61046927SAndroid Build Coastguard Worker * Note that Linux only allows decreasing the priority. The original
342*61046927SAndroid Build Coastguard Worker * priority can't be restored.
343*61046927SAndroid Build Coastguard Worker */
344*61046927SAndroid Build Coastguard Worker pthread_setschedparam(queue->threads[index], SCHED_BATCH, &sched_param);
345*61046927SAndroid Build Coastguard Worker #endif
346*61046927SAndroid Build Coastguard Worker }
347*61046927SAndroid Build Coastguard Worker return true;
348*61046927SAndroid Build Coastguard Worker }
349*61046927SAndroid Build Coastguard Worker
350*61046927SAndroid Build Coastguard Worker void
util_queue_adjust_num_threads(struct util_queue * queue,unsigned num_threads,bool locked)351*61046927SAndroid Build Coastguard Worker util_queue_adjust_num_threads(struct util_queue *queue, unsigned num_threads,
352*61046927SAndroid Build Coastguard Worker bool locked)
353*61046927SAndroid Build Coastguard Worker {
354*61046927SAndroid Build Coastguard Worker num_threads = MIN2(num_threads, queue->max_threads);
355*61046927SAndroid Build Coastguard Worker num_threads = MAX2(num_threads, 1);
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker if (!locked)
358*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
359*61046927SAndroid Build Coastguard Worker
360*61046927SAndroid Build Coastguard Worker unsigned old_num_threads = queue->num_threads;
361*61046927SAndroid Build Coastguard Worker
362*61046927SAndroid Build Coastguard Worker if (num_threads == old_num_threads) {
363*61046927SAndroid Build Coastguard Worker if (!locked)
364*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
365*61046927SAndroid Build Coastguard Worker return;
366*61046927SAndroid Build Coastguard Worker }
367*61046927SAndroid Build Coastguard Worker
368*61046927SAndroid Build Coastguard Worker if (num_threads < old_num_threads) {
369*61046927SAndroid Build Coastguard Worker util_queue_kill_threads(queue, num_threads, true);
370*61046927SAndroid Build Coastguard Worker if (!locked)
371*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
372*61046927SAndroid Build Coastguard Worker return;
373*61046927SAndroid Build Coastguard Worker }
374*61046927SAndroid Build Coastguard Worker
375*61046927SAndroid Build Coastguard Worker /* Create threads.
376*61046927SAndroid Build Coastguard Worker *
377*61046927SAndroid Build Coastguard Worker * We need to update num_threads first, because threads terminate
378*61046927SAndroid Build Coastguard Worker * when thread_index < num_threads.
379*61046927SAndroid Build Coastguard Worker */
380*61046927SAndroid Build Coastguard Worker queue->num_threads = num_threads;
381*61046927SAndroid Build Coastguard Worker for (unsigned i = old_num_threads; i < num_threads; i++) {
382*61046927SAndroid Build Coastguard Worker if (!util_queue_create_thread(queue, i)) {
383*61046927SAndroid Build Coastguard Worker queue->num_threads = i;
384*61046927SAndroid Build Coastguard Worker break;
385*61046927SAndroid Build Coastguard Worker }
386*61046927SAndroid Build Coastguard Worker }
387*61046927SAndroid Build Coastguard Worker
388*61046927SAndroid Build Coastguard Worker if (!locked)
389*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
390*61046927SAndroid Build Coastguard Worker }
391*61046927SAndroid Build Coastguard Worker
392*61046927SAndroid Build Coastguard Worker bool
util_queue_init(struct util_queue * queue,const char * name,unsigned max_jobs,unsigned num_threads,unsigned flags,void * global_data)393*61046927SAndroid Build Coastguard Worker util_queue_init(struct util_queue *queue,
394*61046927SAndroid Build Coastguard Worker const char *name,
395*61046927SAndroid Build Coastguard Worker unsigned max_jobs,
396*61046927SAndroid Build Coastguard Worker unsigned num_threads,
397*61046927SAndroid Build Coastguard Worker unsigned flags,
398*61046927SAndroid Build Coastguard Worker void *global_data)
399*61046927SAndroid Build Coastguard Worker {
400*61046927SAndroid Build Coastguard Worker unsigned i;
401*61046927SAndroid Build Coastguard Worker
402*61046927SAndroid Build Coastguard Worker /* Form the thread name from process_name and name, limited to 13
403*61046927SAndroid Build Coastguard Worker * characters. Characters 14-15 are reserved for the thread number.
404*61046927SAndroid Build Coastguard Worker * Character 16 should be 0. Final form: "process:name12"
405*61046927SAndroid Build Coastguard Worker *
406*61046927SAndroid Build Coastguard Worker * If name is too long, it's truncated. If any space is left, the process
407*61046927SAndroid Build Coastguard Worker * name fills it.
408*61046927SAndroid Build Coastguard Worker */
409*61046927SAndroid Build Coastguard Worker const char *process_name = util_get_process_name();
410*61046927SAndroid Build Coastguard Worker int process_len = process_name ? strlen(process_name) : 0;
411*61046927SAndroid Build Coastguard Worker int name_len = strlen(name);
412*61046927SAndroid Build Coastguard Worker const int max_chars = sizeof(queue->name) - 1;
413*61046927SAndroid Build Coastguard Worker
414*61046927SAndroid Build Coastguard Worker name_len = MIN2(name_len, max_chars);
415*61046927SAndroid Build Coastguard Worker
416*61046927SAndroid Build Coastguard Worker /* See if there is any space left for the process name, reserve 1 for
417*61046927SAndroid Build Coastguard Worker * the colon. */
418*61046927SAndroid Build Coastguard Worker process_len = MIN2(process_len, max_chars - name_len - 1);
419*61046927SAndroid Build Coastguard Worker process_len = MAX2(process_len, 0);
420*61046927SAndroid Build Coastguard Worker
421*61046927SAndroid Build Coastguard Worker memset(queue, 0, sizeof(*queue));
422*61046927SAndroid Build Coastguard Worker
423*61046927SAndroid Build Coastguard Worker if (process_len) {
424*61046927SAndroid Build Coastguard Worker snprintf(queue->name, sizeof(queue->name), "%.*s:%s",
425*61046927SAndroid Build Coastguard Worker process_len, process_name, name);
426*61046927SAndroid Build Coastguard Worker } else {
427*61046927SAndroid Build Coastguard Worker snprintf(queue->name, sizeof(queue->name), "%s", name);
428*61046927SAndroid Build Coastguard Worker }
429*61046927SAndroid Build Coastguard Worker
430*61046927SAndroid Build Coastguard Worker queue->create_threads_on_demand = true;
431*61046927SAndroid Build Coastguard Worker queue->flags = flags;
432*61046927SAndroid Build Coastguard Worker queue->max_threads = num_threads;
433*61046927SAndroid Build Coastguard Worker queue->num_threads = 1;
434*61046927SAndroid Build Coastguard Worker queue->max_jobs = max_jobs;
435*61046927SAndroid Build Coastguard Worker queue->global_data = global_data;
436*61046927SAndroid Build Coastguard Worker
437*61046927SAndroid Build Coastguard Worker (void) mtx_init(&queue->lock, mtx_plain);
438*61046927SAndroid Build Coastguard Worker
439*61046927SAndroid Build Coastguard Worker queue->num_queued = 0;
440*61046927SAndroid Build Coastguard Worker cnd_init(&queue->has_queued_cond);
441*61046927SAndroid Build Coastguard Worker cnd_init(&queue->has_space_cond);
442*61046927SAndroid Build Coastguard Worker
443*61046927SAndroid Build Coastguard Worker queue->jobs = (struct util_queue_job*)
444*61046927SAndroid Build Coastguard Worker calloc(max_jobs, sizeof(struct util_queue_job));
445*61046927SAndroid Build Coastguard Worker if (!queue->jobs)
446*61046927SAndroid Build Coastguard Worker goto fail;
447*61046927SAndroid Build Coastguard Worker
448*61046927SAndroid Build Coastguard Worker queue->threads = (thrd_t*) calloc(queue->max_threads, sizeof(thrd_t));
449*61046927SAndroid Build Coastguard Worker if (!queue->threads)
450*61046927SAndroid Build Coastguard Worker goto fail;
451*61046927SAndroid Build Coastguard Worker
452*61046927SAndroid Build Coastguard Worker /* start threads */
453*61046927SAndroid Build Coastguard Worker for (i = 0; i < queue->num_threads; i++) {
454*61046927SAndroid Build Coastguard Worker if (!util_queue_create_thread(queue, i)) {
455*61046927SAndroid Build Coastguard Worker if (i == 0) {
456*61046927SAndroid Build Coastguard Worker /* no threads created, fail */
457*61046927SAndroid Build Coastguard Worker goto fail;
458*61046927SAndroid Build Coastguard Worker } else {
459*61046927SAndroid Build Coastguard Worker /* at least one thread created, so use it */
460*61046927SAndroid Build Coastguard Worker queue->num_threads = i;
461*61046927SAndroid Build Coastguard Worker break;
462*61046927SAndroid Build Coastguard Worker }
463*61046927SAndroid Build Coastguard Worker }
464*61046927SAndroid Build Coastguard Worker }
465*61046927SAndroid Build Coastguard Worker
466*61046927SAndroid Build Coastguard Worker add_to_atexit_list(queue);
467*61046927SAndroid Build Coastguard Worker return true;
468*61046927SAndroid Build Coastguard Worker
469*61046927SAndroid Build Coastguard Worker fail:
470*61046927SAndroid Build Coastguard Worker free(queue->threads);
471*61046927SAndroid Build Coastguard Worker
472*61046927SAndroid Build Coastguard Worker if (queue->jobs) {
473*61046927SAndroid Build Coastguard Worker cnd_destroy(&queue->has_space_cond);
474*61046927SAndroid Build Coastguard Worker cnd_destroy(&queue->has_queued_cond);
475*61046927SAndroid Build Coastguard Worker mtx_destroy(&queue->lock);
476*61046927SAndroid Build Coastguard Worker free(queue->jobs);
477*61046927SAndroid Build Coastguard Worker }
478*61046927SAndroid Build Coastguard Worker /* also util_queue_is_initialized can be used to check for success */
479*61046927SAndroid Build Coastguard Worker memset(queue, 0, sizeof(*queue));
480*61046927SAndroid Build Coastguard Worker return false;
481*61046927SAndroid Build Coastguard Worker }
482*61046927SAndroid Build Coastguard Worker
483*61046927SAndroid Build Coastguard Worker static void
util_queue_kill_threads(struct util_queue * queue,unsigned keep_num_threads,bool locked)484*61046927SAndroid Build Coastguard Worker util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads,
485*61046927SAndroid Build Coastguard Worker bool locked)
486*61046927SAndroid Build Coastguard Worker {
487*61046927SAndroid Build Coastguard Worker /* Signal all threads to terminate. */
488*61046927SAndroid Build Coastguard Worker if (!locked)
489*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
490*61046927SAndroid Build Coastguard Worker
491*61046927SAndroid Build Coastguard Worker if (keep_num_threads >= queue->num_threads) {
492*61046927SAndroid Build Coastguard Worker if (!locked)
493*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
494*61046927SAndroid Build Coastguard Worker return;
495*61046927SAndroid Build Coastguard Worker }
496*61046927SAndroid Build Coastguard Worker
497*61046927SAndroid Build Coastguard Worker unsigned old_num_threads = queue->num_threads;
498*61046927SAndroid Build Coastguard Worker /* Setting num_threads is what causes the threads to terminate.
499*61046927SAndroid Build Coastguard Worker * Then cnd_broadcast wakes them up and they will exit their function.
500*61046927SAndroid Build Coastguard Worker */
501*61046927SAndroid Build Coastguard Worker queue->num_threads = keep_num_threads;
502*61046927SAndroid Build Coastguard Worker cnd_broadcast(&queue->has_queued_cond);
503*61046927SAndroid Build Coastguard Worker
504*61046927SAndroid Build Coastguard Worker /* Wait for threads to terminate. */
505*61046927SAndroid Build Coastguard Worker if (keep_num_threads < old_num_threads) {
506*61046927SAndroid Build Coastguard Worker /* We need to unlock the mutex to allow threads to terminate. */
507*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
508*61046927SAndroid Build Coastguard Worker for (unsigned i = keep_num_threads; i < old_num_threads; i++)
509*61046927SAndroid Build Coastguard Worker thrd_join(queue->threads[i], NULL);
510*61046927SAndroid Build Coastguard Worker if (locked)
511*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
512*61046927SAndroid Build Coastguard Worker } else {
513*61046927SAndroid Build Coastguard Worker if (!locked)
514*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
515*61046927SAndroid Build Coastguard Worker }
516*61046927SAndroid Build Coastguard Worker }
517*61046927SAndroid Build Coastguard Worker
518*61046927SAndroid Build Coastguard Worker static void
util_queue_finish_execute(void * data,void * gdata,int num_thread)519*61046927SAndroid Build Coastguard Worker util_queue_finish_execute(void *data, void *gdata, int num_thread)
520*61046927SAndroid Build Coastguard Worker {
521*61046927SAndroid Build Coastguard Worker util_barrier *barrier = data;
522*61046927SAndroid Build Coastguard Worker if (util_barrier_wait(barrier))
523*61046927SAndroid Build Coastguard Worker util_barrier_destroy(barrier);
524*61046927SAndroid Build Coastguard Worker }
525*61046927SAndroid Build Coastguard Worker
526*61046927SAndroid Build Coastguard Worker void
util_queue_destroy(struct util_queue * queue)527*61046927SAndroid Build Coastguard Worker util_queue_destroy(struct util_queue *queue)
528*61046927SAndroid Build Coastguard Worker {
529*61046927SAndroid Build Coastguard Worker util_queue_kill_threads(queue, 0, false);
530*61046927SAndroid Build Coastguard Worker
531*61046927SAndroid Build Coastguard Worker /* This makes it safe to call on a queue that failed util_queue_init. */
532*61046927SAndroid Build Coastguard Worker if (queue->head.next != NULL)
533*61046927SAndroid Build Coastguard Worker remove_from_atexit_list(queue);
534*61046927SAndroid Build Coastguard Worker
535*61046927SAndroid Build Coastguard Worker cnd_destroy(&queue->has_space_cond);
536*61046927SAndroid Build Coastguard Worker cnd_destroy(&queue->has_queued_cond);
537*61046927SAndroid Build Coastguard Worker mtx_destroy(&queue->lock);
538*61046927SAndroid Build Coastguard Worker free(queue->jobs);
539*61046927SAndroid Build Coastguard Worker free(queue->threads);
540*61046927SAndroid Build Coastguard Worker }
541*61046927SAndroid Build Coastguard Worker
542*61046927SAndroid Build Coastguard Worker static void
util_queue_add_job_locked(struct util_queue * queue,void * job,struct util_queue_fence * fence,util_queue_execute_func execute,util_queue_execute_func cleanup,const size_t job_size,bool locked)543*61046927SAndroid Build Coastguard Worker util_queue_add_job_locked(struct util_queue *queue,
544*61046927SAndroid Build Coastguard Worker void *job,
545*61046927SAndroid Build Coastguard Worker struct util_queue_fence *fence,
546*61046927SAndroid Build Coastguard Worker util_queue_execute_func execute,
547*61046927SAndroid Build Coastguard Worker util_queue_execute_func cleanup,
548*61046927SAndroid Build Coastguard Worker const size_t job_size,
549*61046927SAndroid Build Coastguard Worker bool locked)
550*61046927SAndroid Build Coastguard Worker {
551*61046927SAndroid Build Coastguard Worker struct util_queue_job *ptr;
552*61046927SAndroid Build Coastguard Worker
553*61046927SAndroid Build Coastguard Worker if (!locked)
554*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
555*61046927SAndroid Build Coastguard Worker if (queue->num_threads == 0) {
556*61046927SAndroid Build Coastguard Worker if (!locked)
557*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
558*61046927SAndroid Build Coastguard Worker /* well no good option here, but any leaks will be
559*61046927SAndroid Build Coastguard Worker * short-lived as things are shutting down..
560*61046927SAndroid Build Coastguard Worker */
561*61046927SAndroid Build Coastguard Worker return;
562*61046927SAndroid Build Coastguard Worker }
563*61046927SAndroid Build Coastguard Worker
564*61046927SAndroid Build Coastguard Worker if (fence)
565*61046927SAndroid Build Coastguard Worker util_queue_fence_reset(fence);
566*61046927SAndroid Build Coastguard Worker
567*61046927SAndroid Build Coastguard Worker assert(queue->num_queued >= 0 && queue->num_queued <= queue->max_jobs);
568*61046927SAndroid Build Coastguard Worker
569*61046927SAndroid Build Coastguard Worker /* Scale the number of threads up if there's already one job waiting. */
570*61046927SAndroid Build Coastguard Worker if (queue->num_queued > 0 &&
571*61046927SAndroid Build Coastguard Worker queue->create_threads_on_demand &&
572*61046927SAndroid Build Coastguard Worker execute != util_queue_finish_execute &&
573*61046927SAndroid Build Coastguard Worker queue->num_threads < queue->max_threads) {
574*61046927SAndroid Build Coastguard Worker util_queue_adjust_num_threads(queue, queue->num_threads + 1, true);
575*61046927SAndroid Build Coastguard Worker }
576*61046927SAndroid Build Coastguard Worker
577*61046927SAndroid Build Coastguard Worker if (queue->num_queued == queue->max_jobs) {
578*61046927SAndroid Build Coastguard Worker if (queue->flags & UTIL_QUEUE_INIT_RESIZE_IF_FULL &&
579*61046927SAndroid Build Coastguard Worker queue->total_jobs_size + job_size < S_256MB) {
580*61046927SAndroid Build Coastguard Worker /* If the queue is full, make it larger to avoid waiting for a free
581*61046927SAndroid Build Coastguard Worker * slot.
582*61046927SAndroid Build Coastguard Worker */
583*61046927SAndroid Build Coastguard Worker unsigned new_max_jobs = queue->max_jobs + 8;
584*61046927SAndroid Build Coastguard Worker struct util_queue_job *jobs =
585*61046927SAndroid Build Coastguard Worker (struct util_queue_job*)calloc(new_max_jobs,
586*61046927SAndroid Build Coastguard Worker sizeof(struct util_queue_job));
587*61046927SAndroid Build Coastguard Worker assert(jobs);
588*61046927SAndroid Build Coastguard Worker
589*61046927SAndroid Build Coastguard Worker /* Copy all queued jobs into the new list. */
590*61046927SAndroid Build Coastguard Worker unsigned num_jobs = 0;
591*61046927SAndroid Build Coastguard Worker unsigned i = queue->read_idx;
592*61046927SAndroid Build Coastguard Worker
593*61046927SAndroid Build Coastguard Worker do {
594*61046927SAndroid Build Coastguard Worker jobs[num_jobs++] = queue->jobs[i];
595*61046927SAndroid Build Coastguard Worker i = (i + 1) % queue->max_jobs;
596*61046927SAndroid Build Coastguard Worker } while (i != queue->write_idx);
597*61046927SAndroid Build Coastguard Worker
598*61046927SAndroid Build Coastguard Worker assert(num_jobs == queue->num_queued);
599*61046927SAndroid Build Coastguard Worker
600*61046927SAndroid Build Coastguard Worker free(queue->jobs);
601*61046927SAndroid Build Coastguard Worker queue->jobs = jobs;
602*61046927SAndroid Build Coastguard Worker queue->read_idx = 0;
603*61046927SAndroid Build Coastguard Worker queue->write_idx = num_jobs;
604*61046927SAndroid Build Coastguard Worker queue->max_jobs = new_max_jobs;
605*61046927SAndroid Build Coastguard Worker } else {
606*61046927SAndroid Build Coastguard Worker /* Wait until there is a free slot. */
607*61046927SAndroid Build Coastguard Worker while (queue->num_queued == queue->max_jobs)
608*61046927SAndroid Build Coastguard Worker cnd_wait(&queue->has_space_cond, &queue->lock);
609*61046927SAndroid Build Coastguard Worker }
610*61046927SAndroid Build Coastguard Worker }
611*61046927SAndroid Build Coastguard Worker
612*61046927SAndroid Build Coastguard Worker ptr = &queue->jobs[queue->write_idx];
613*61046927SAndroid Build Coastguard Worker assert(ptr->job == NULL);
614*61046927SAndroid Build Coastguard Worker ptr->job = job;
615*61046927SAndroid Build Coastguard Worker ptr->global_data = queue->global_data;
616*61046927SAndroid Build Coastguard Worker ptr->fence = fence;
617*61046927SAndroid Build Coastguard Worker ptr->execute = execute;
618*61046927SAndroid Build Coastguard Worker ptr->cleanup = cleanup;
619*61046927SAndroid Build Coastguard Worker ptr->job_size = job_size;
620*61046927SAndroid Build Coastguard Worker
621*61046927SAndroid Build Coastguard Worker queue->write_idx = (queue->write_idx + 1) % queue->max_jobs;
622*61046927SAndroid Build Coastguard Worker queue->total_jobs_size += ptr->job_size;
623*61046927SAndroid Build Coastguard Worker
624*61046927SAndroid Build Coastguard Worker queue->num_queued++;
625*61046927SAndroid Build Coastguard Worker cnd_signal(&queue->has_queued_cond);
626*61046927SAndroid Build Coastguard Worker if (!locked)
627*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
628*61046927SAndroid Build Coastguard Worker }
629*61046927SAndroid Build Coastguard Worker
630*61046927SAndroid Build Coastguard Worker void
util_queue_add_job(struct util_queue * queue,void * job,struct util_queue_fence * fence,util_queue_execute_func execute,util_queue_execute_func cleanup,const size_t job_size)631*61046927SAndroid Build Coastguard Worker util_queue_add_job(struct util_queue *queue,
632*61046927SAndroid Build Coastguard Worker void *job,
633*61046927SAndroid Build Coastguard Worker struct util_queue_fence *fence,
634*61046927SAndroid Build Coastguard Worker util_queue_execute_func execute,
635*61046927SAndroid Build Coastguard Worker util_queue_execute_func cleanup,
636*61046927SAndroid Build Coastguard Worker const size_t job_size)
637*61046927SAndroid Build Coastguard Worker {
638*61046927SAndroid Build Coastguard Worker util_queue_add_job_locked(queue, job, fence, execute, cleanup, job_size,
639*61046927SAndroid Build Coastguard Worker false);
640*61046927SAndroid Build Coastguard Worker }
641*61046927SAndroid Build Coastguard Worker
642*61046927SAndroid Build Coastguard Worker /**
643*61046927SAndroid Build Coastguard Worker * Remove a queued job. If the job hasn't started execution, it's removed from
644*61046927SAndroid Build Coastguard Worker * the queue. If the job has started execution, the function waits for it to
645*61046927SAndroid Build Coastguard Worker * complete.
646*61046927SAndroid Build Coastguard Worker *
647*61046927SAndroid Build Coastguard Worker * In all cases, the fence is signalled when the function returns.
648*61046927SAndroid Build Coastguard Worker *
649*61046927SAndroid Build Coastguard Worker * The function can be used when destroying an object associated with the job
650*61046927SAndroid Build Coastguard Worker * when you don't care about the job completion state.
651*61046927SAndroid Build Coastguard Worker */
652*61046927SAndroid Build Coastguard Worker void
util_queue_drop_job(struct util_queue * queue,struct util_queue_fence * fence)653*61046927SAndroid Build Coastguard Worker util_queue_drop_job(struct util_queue *queue, struct util_queue_fence *fence)
654*61046927SAndroid Build Coastguard Worker {
655*61046927SAndroid Build Coastguard Worker bool removed = false;
656*61046927SAndroid Build Coastguard Worker
657*61046927SAndroid Build Coastguard Worker if (util_queue_fence_is_signalled(fence))
658*61046927SAndroid Build Coastguard Worker return;
659*61046927SAndroid Build Coastguard Worker
660*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
661*61046927SAndroid Build Coastguard Worker for (unsigned i = queue->read_idx; i != queue->write_idx;
662*61046927SAndroid Build Coastguard Worker i = (i + 1) % queue->max_jobs) {
663*61046927SAndroid Build Coastguard Worker if (queue->jobs[i].fence == fence) {
664*61046927SAndroid Build Coastguard Worker if (queue->jobs[i].cleanup)
665*61046927SAndroid Build Coastguard Worker queue->jobs[i].cleanup(queue->jobs[i].job, queue->global_data, -1);
666*61046927SAndroid Build Coastguard Worker
667*61046927SAndroid Build Coastguard Worker /* Just clear it. The threads will treat as a no-op job. */
668*61046927SAndroid Build Coastguard Worker memset(&queue->jobs[i], 0, sizeof(queue->jobs[i]));
669*61046927SAndroid Build Coastguard Worker removed = true;
670*61046927SAndroid Build Coastguard Worker break;
671*61046927SAndroid Build Coastguard Worker }
672*61046927SAndroid Build Coastguard Worker }
673*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
674*61046927SAndroid Build Coastguard Worker
675*61046927SAndroid Build Coastguard Worker if (removed)
676*61046927SAndroid Build Coastguard Worker util_queue_fence_signal(fence);
677*61046927SAndroid Build Coastguard Worker else
678*61046927SAndroid Build Coastguard Worker util_queue_fence_wait(fence);
679*61046927SAndroid Build Coastguard Worker }
680*61046927SAndroid Build Coastguard Worker
681*61046927SAndroid Build Coastguard Worker /**
682*61046927SAndroid Build Coastguard Worker * Wait until all previously added jobs have completed.
683*61046927SAndroid Build Coastguard Worker */
684*61046927SAndroid Build Coastguard Worker void
util_queue_finish(struct util_queue * queue)685*61046927SAndroid Build Coastguard Worker util_queue_finish(struct util_queue *queue)
686*61046927SAndroid Build Coastguard Worker {
687*61046927SAndroid Build Coastguard Worker util_barrier barrier;
688*61046927SAndroid Build Coastguard Worker struct util_queue_fence *fences;
689*61046927SAndroid Build Coastguard Worker
690*61046927SAndroid Build Coastguard Worker /* If 2 threads were adding jobs for 2 different barries at the same time,
691*61046927SAndroid Build Coastguard Worker * a deadlock would happen, because 1 barrier requires that all threads
692*61046927SAndroid Build Coastguard Worker * wait for it exclusively.
693*61046927SAndroid Build Coastguard Worker */
694*61046927SAndroid Build Coastguard Worker mtx_lock(&queue->lock);
695*61046927SAndroid Build Coastguard Worker
696*61046927SAndroid Build Coastguard Worker /* The number of threads can be changed to 0, e.g. by the atexit handler. */
697*61046927SAndroid Build Coastguard Worker if (!queue->num_threads) {
698*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
699*61046927SAndroid Build Coastguard Worker return;
700*61046927SAndroid Build Coastguard Worker }
701*61046927SAndroid Build Coastguard Worker
702*61046927SAndroid Build Coastguard Worker /* We need to disable adding new threads in util_queue_add_job because
703*61046927SAndroid Build Coastguard Worker * the finish operation requires a fixed number of threads.
704*61046927SAndroid Build Coastguard Worker *
705*61046927SAndroid Build Coastguard Worker * Also note that util_queue_add_job can unlock the mutex if there is not
706*61046927SAndroid Build Coastguard Worker * enough space in the queue and wait for space.
707*61046927SAndroid Build Coastguard Worker */
708*61046927SAndroid Build Coastguard Worker queue->create_threads_on_demand = false;
709*61046927SAndroid Build Coastguard Worker
710*61046927SAndroid Build Coastguard Worker fences = malloc(queue->num_threads * sizeof(*fences));
711*61046927SAndroid Build Coastguard Worker util_barrier_init(&barrier, queue->num_threads);
712*61046927SAndroid Build Coastguard Worker
713*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < queue->num_threads; ++i) {
714*61046927SAndroid Build Coastguard Worker util_queue_fence_init(&fences[i]);
715*61046927SAndroid Build Coastguard Worker util_queue_add_job_locked(queue, &barrier, &fences[i],
716*61046927SAndroid Build Coastguard Worker util_queue_finish_execute, NULL, 0, true);
717*61046927SAndroid Build Coastguard Worker }
718*61046927SAndroid Build Coastguard Worker queue->create_threads_on_demand = true;
719*61046927SAndroid Build Coastguard Worker mtx_unlock(&queue->lock);
720*61046927SAndroid Build Coastguard Worker
721*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < queue->num_threads; ++i) {
722*61046927SAndroid Build Coastguard Worker util_queue_fence_wait(&fences[i]);
723*61046927SAndroid Build Coastguard Worker util_queue_fence_destroy(&fences[i]);
724*61046927SAndroid Build Coastguard Worker }
725*61046927SAndroid Build Coastguard Worker
726*61046927SAndroid Build Coastguard Worker free(fences);
727*61046927SAndroid Build Coastguard Worker }
728*61046927SAndroid Build Coastguard Worker
729*61046927SAndroid Build Coastguard Worker int64_t
util_queue_get_thread_time_nano(struct util_queue * queue,unsigned thread_index)730*61046927SAndroid Build Coastguard Worker util_queue_get_thread_time_nano(struct util_queue *queue, unsigned thread_index)
731*61046927SAndroid Build Coastguard Worker {
732*61046927SAndroid Build Coastguard Worker /* Allow some flexibility by not raising an error. */
733*61046927SAndroid Build Coastguard Worker if (thread_index >= queue->num_threads)
734*61046927SAndroid Build Coastguard Worker return 0;
735*61046927SAndroid Build Coastguard Worker
736*61046927SAndroid Build Coastguard Worker return util_thread_get_time_nano(queue->threads[thread_index]);
737*61046927SAndroid Build Coastguard Worker }
738