1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2012 Intel Corporation
3*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker */
5*61046927SAndroid Build Coastguard Worker
6*61046927SAndroid Build Coastguard Worker #include "swapchain9.h"
7*61046927SAndroid Build Coastguard Worker #include "surface9.h"
8*61046927SAndroid Build Coastguard Worker #include "device9.h"
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include "nine_helpers.h"
11*61046927SAndroid Build Coastguard Worker #include "nine_pipe.h"
12*61046927SAndroid Build Coastguard Worker #include "nine_dump.h"
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Worker #include "util/u_inlines.h"
15*61046927SAndroid Build Coastguard Worker #include "util/u_surface.h"
16*61046927SAndroid Build Coastguard Worker #include "hud/hud_context.h"
17*61046927SAndroid Build Coastguard Worker #include "frontend/drm_driver.h"
18*61046927SAndroid Build Coastguard Worker
19*61046927SAndroid Build Coastguard Worker #include "util/u_thread.h"
20*61046927SAndroid Build Coastguard Worker #include "threadpool.h"
21*61046927SAndroid Build Coastguard Worker
22*61046927SAndroid Build Coastguard Worker /* POSIX thread function */
23*61046927SAndroid Build Coastguard Worker static void *
threadpool_worker(void * data)24*61046927SAndroid Build Coastguard Worker threadpool_worker(void *data)
25*61046927SAndroid Build Coastguard Worker {
26*61046927SAndroid Build Coastguard Worker struct threadpool *pool = data;
27*61046927SAndroid Build Coastguard Worker
28*61046927SAndroid Build Coastguard Worker pthread_mutex_lock(&pool->m);
29*61046927SAndroid Build Coastguard Worker
30*61046927SAndroid Build Coastguard Worker while (!pool->shutdown) {
31*61046927SAndroid Build Coastguard Worker struct threadpool_task *task;
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker /* Block (dropping the lock) until new work arrives for us. */
34*61046927SAndroid Build Coastguard Worker while (!pool->workqueue && !pool->shutdown)
35*61046927SAndroid Build Coastguard Worker pthread_cond_wait(&pool->new_work, &pool->m);
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker if (pool->shutdown)
38*61046927SAndroid Build Coastguard Worker break;
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker /* Pull the first task from the list. We don't free it -- it now lacks
41*61046927SAndroid Build Coastguard Worker * a reference other than the worker creator's, whose responsibility it
42*61046927SAndroid Build Coastguard Worker * is to call threadpool_wait_for_work() to free it.
43*61046927SAndroid Build Coastguard Worker */
44*61046927SAndroid Build Coastguard Worker task = pool->workqueue;
45*61046927SAndroid Build Coastguard Worker pool->workqueue = task->next;
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker /* Call the task's work func. */
48*61046927SAndroid Build Coastguard Worker pthread_mutex_unlock(&pool->m);
49*61046927SAndroid Build Coastguard Worker task->work(task->data);
50*61046927SAndroid Build Coastguard Worker pthread_mutex_lock(&pool->m);
51*61046927SAndroid Build Coastguard Worker task->finished = true;
52*61046927SAndroid Build Coastguard Worker pthread_cond_broadcast(&task->finish);
53*61046927SAndroid Build Coastguard Worker }
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker pthread_mutex_unlock(&pool->m);
56*61046927SAndroid Build Coastguard Worker
57*61046927SAndroid Build Coastguard Worker return NULL;
58*61046927SAndroid Build Coastguard Worker }
59*61046927SAndroid Build Coastguard Worker
60*61046927SAndroid Build Coastguard Worker /* Windows thread function */
61*61046927SAndroid Build Coastguard Worker static DWORD NINE_WINAPI
wthreadpool_worker(void * data)62*61046927SAndroid Build Coastguard Worker wthreadpool_worker(void *data)
63*61046927SAndroid Build Coastguard Worker {
64*61046927SAndroid Build Coastguard Worker threadpool_worker(data);
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Worker return 0;
67*61046927SAndroid Build Coastguard Worker }
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker struct threadpool *
_mesa_threadpool_create(struct NineSwapChain9 * swapchain)70*61046927SAndroid Build Coastguard Worker _mesa_threadpool_create(struct NineSwapChain9 *swapchain)
71*61046927SAndroid Build Coastguard Worker {
72*61046927SAndroid Build Coastguard Worker struct threadpool *pool = calloc(1, sizeof(*pool));
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker if (!pool)
75*61046927SAndroid Build Coastguard Worker return NULL;
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker pthread_mutex_init(&pool->m, NULL);
78*61046927SAndroid Build Coastguard Worker pthread_cond_init(&pool->new_work, NULL);
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker /* This uses WINE's CreateThread, so the thread function needs to use
81*61046927SAndroid Build Coastguard Worker * the Windows ABI */
82*61046927SAndroid Build Coastguard Worker pool->wthread = NineSwapChain9_CreateThread(swapchain, wthreadpool_worker, pool);
83*61046927SAndroid Build Coastguard Worker if (!pool->wthread) {
84*61046927SAndroid Build Coastguard Worker /* using pthread as fallback */
85*61046927SAndroid Build Coastguard Worker pthread_create(&pool->pthread, NULL, threadpool_worker, pool);
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker return pool;
88*61046927SAndroid Build Coastguard Worker }
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker void
_mesa_threadpool_destroy(struct NineSwapChain9 * swapchain,struct threadpool * pool)91*61046927SAndroid Build Coastguard Worker _mesa_threadpool_destroy(struct NineSwapChain9 *swapchain, struct threadpool *pool)
92*61046927SAndroid Build Coastguard Worker {
93*61046927SAndroid Build Coastguard Worker if (!pool)
94*61046927SAndroid Build Coastguard Worker return;
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker pthread_mutex_lock(&pool->m);
97*61046927SAndroid Build Coastguard Worker pool->shutdown = true;
98*61046927SAndroid Build Coastguard Worker pthread_cond_broadcast(&pool->new_work);
99*61046927SAndroid Build Coastguard Worker pthread_mutex_unlock(&pool->m);
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker if (pool->wthread) {
102*61046927SAndroid Build Coastguard Worker NineSwapChain9_WaitForThread(swapchain, pool->wthread);
103*61046927SAndroid Build Coastguard Worker } else {
104*61046927SAndroid Build Coastguard Worker pthread_join(pool->pthread, NULL);
105*61046927SAndroid Build Coastguard Worker }
106*61046927SAndroid Build Coastguard Worker
107*61046927SAndroid Build Coastguard Worker pthread_cond_destroy(&pool->new_work);
108*61046927SAndroid Build Coastguard Worker pthread_mutex_destroy(&pool->m);
109*61046927SAndroid Build Coastguard Worker free(pool);
110*61046927SAndroid Build Coastguard Worker }
111*61046927SAndroid Build Coastguard Worker
112*61046927SAndroid Build Coastguard Worker /**
113*61046927SAndroid Build Coastguard Worker * Queues a request for the work function to be asynchronously executed by the
114*61046927SAndroid Build Coastguard Worker * thread pool.
115*61046927SAndroid Build Coastguard Worker *
116*61046927SAndroid Build Coastguard Worker * The work func will get the "data" argument as its parameter -- any
117*61046927SAndroid Build Coastguard Worker * communication between the caller and the work function will occur through
118*61046927SAndroid Build Coastguard Worker * that.
119*61046927SAndroid Build Coastguard Worker *
120*61046927SAndroid Build Coastguard Worker * If there is an error, the work function is called immediately and NULL is
121*61046927SAndroid Build Coastguard Worker * returned.
122*61046927SAndroid Build Coastguard Worker */
123*61046927SAndroid Build Coastguard Worker struct threadpool_task *
_mesa_threadpool_queue_task(struct threadpool * pool,threadpool_task_func work,void * data)124*61046927SAndroid Build Coastguard Worker _mesa_threadpool_queue_task(struct threadpool *pool,
125*61046927SAndroid Build Coastguard Worker threadpool_task_func work, void *data)
126*61046927SAndroid Build Coastguard Worker {
127*61046927SAndroid Build Coastguard Worker struct threadpool_task *task, *previous;
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker if (!pool) {
130*61046927SAndroid Build Coastguard Worker work(data);
131*61046927SAndroid Build Coastguard Worker return NULL;
132*61046927SAndroid Build Coastguard Worker }
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker task = calloc(1, sizeof(*task));
135*61046927SAndroid Build Coastguard Worker if (!task) {
136*61046927SAndroid Build Coastguard Worker work(data);
137*61046927SAndroid Build Coastguard Worker return NULL;
138*61046927SAndroid Build Coastguard Worker }
139*61046927SAndroid Build Coastguard Worker
140*61046927SAndroid Build Coastguard Worker task->work = work;
141*61046927SAndroid Build Coastguard Worker task->data = data;
142*61046927SAndroid Build Coastguard Worker task->next = NULL;
143*61046927SAndroid Build Coastguard Worker pthread_cond_init(&task->finish, NULL);
144*61046927SAndroid Build Coastguard Worker
145*61046927SAndroid Build Coastguard Worker pthread_mutex_lock(&pool->m);
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker if (!pool->workqueue) {
148*61046927SAndroid Build Coastguard Worker pool->workqueue = task;
149*61046927SAndroid Build Coastguard Worker } else {
150*61046927SAndroid Build Coastguard Worker previous = pool->workqueue;
151*61046927SAndroid Build Coastguard Worker while (previous && previous->next)
152*61046927SAndroid Build Coastguard Worker previous = previous->next;
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker previous->next = task;
155*61046927SAndroid Build Coastguard Worker }
156*61046927SAndroid Build Coastguard Worker pthread_cond_signal(&pool->new_work);
157*61046927SAndroid Build Coastguard Worker pthread_mutex_unlock(&pool->m);
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker return task;
160*61046927SAndroid Build Coastguard Worker }
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker /**
163*61046927SAndroid Build Coastguard Worker * Blocks on the completion of the given task and frees the task.
164*61046927SAndroid Build Coastguard Worker */
165*61046927SAndroid Build Coastguard Worker void
_mesa_threadpool_wait_for_task(struct threadpool * pool,struct threadpool_task ** task_handle)166*61046927SAndroid Build Coastguard Worker _mesa_threadpool_wait_for_task(struct threadpool *pool,
167*61046927SAndroid Build Coastguard Worker struct threadpool_task **task_handle)
168*61046927SAndroid Build Coastguard Worker {
169*61046927SAndroid Build Coastguard Worker struct threadpool_task *task = *task_handle;
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker if (!pool || !task)
172*61046927SAndroid Build Coastguard Worker return;
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker pthread_mutex_lock(&pool->m);
175*61046927SAndroid Build Coastguard Worker while (!task->finished)
176*61046927SAndroid Build Coastguard Worker pthread_cond_wait(&task->finish, &pool->m);
177*61046927SAndroid Build Coastguard Worker pthread_mutex_unlock(&pool->m);
178*61046927SAndroid Build Coastguard Worker
179*61046927SAndroid Build Coastguard Worker pthread_cond_destroy(&task->finish);
180*61046927SAndroid Build Coastguard Worker free(task);
181*61046927SAndroid Build Coastguard Worker *task_handle = NULL;
182*61046927SAndroid Build Coastguard Worker }
183