xref: /aosp_15_r20/external/libwebsockets/lib/misc/threadpool/threadpool.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2010 - 2020 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker  * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker  * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker  * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker  */
24*1c60b9acSAndroid Build Coastguard Worker 
25*1c60b9acSAndroid Build Coastguard Worker #if !defined(_GNU_SOURCE)
26*1c60b9acSAndroid Build Coastguard Worker #define _GNU_SOURCE
27*1c60b9acSAndroid Build Coastguard Worker #endif
28*1c60b9acSAndroid Build Coastguard Worker 
29*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
30*1c60b9acSAndroid Build Coastguard Worker #define HAVE_STRUCT_TIMESPEC
31*1c60b9acSAndroid Build Coastguard Worker #if defined(pid_t)
32*1c60b9acSAndroid Build Coastguard Worker #undef pid_t
33*1c60b9acSAndroid Build Coastguard Worker #endif
34*1c60b9acSAndroid Build Coastguard Worker #endif
35*1c60b9acSAndroid Build Coastguard Worker #include <pthread.h>
36*1c60b9acSAndroid Build Coastguard Worker 
37*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
38*1c60b9acSAndroid Build Coastguard Worker 
39*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
40*1c60b9acSAndroid Build Coastguard Worker #include <stdio.h>
41*1c60b9acSAndroid Build Coastguard Worker 
42*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool;
43*1c60b9acSAndroid Build Coastguard Worker 
44*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool_task {
45*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task	*task_queue_next;
46*1c60b9acSAndroid Build Coastguard Worker 
47*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool		*tp;
48*1c60b9acSAndroid Build Coastguard Worker 	char				name[32];
49*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task_args args;
50*1c60b9acSAndroid Build Coastguard Worker 
51*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_t			list;
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			created;
54*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			acquired;
55*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			done;
56*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			entered_state;
57*1c60b9acSAndroid Build Coastguard Worker 
58*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			acc_running;
59*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			acc_syncing;
60*1c60b9acSAndroid Build Coastguard Worker 
61*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_t			wake_idle;
62*1c60b9acSAndroid Build Coastguard Worker 
63*1c60b9acSAndroid Build Coastguard Worker 	enum lws_threadpool_task_status status;
64*1c60b9acSAndroid Build Coastguard Worker 
65*1c60b9acSAndroid Build Coastguard Worker 	int				late_sync_retries;
66*1c60b9acSAndroid Build Coastguard Worker 
67*1c60b9acSAndroid Build Coastguard Worker 	char				wanted_writeable_cb;
68*1c60b9acSAndroid Build Coastguard Worker 	char				outlive;
69*1c60b9acSAndroid Build Coastguard Worker };
70*1c60b9acSAndroid Build Coastguard Worker 
71*1c60b9acSAndroid Build Coastguard Worker struct lws_pool {
72*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool		*tp;
73*1c60b9acSAndroid Build Coastguard Worker 	pthread_t			thread;
74*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_t			lock; /* part of task wake_idle */
75*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task	*task;
76*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t			acquired;
77*1c60b9acSAndroid Build Coastguard Worker 	int				worker_index;
78*1c60b9acSAndroid Build Coastguard Worker };
79*1c60b9acSAndroid Build Coastguard Worker 
80*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool {
81*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_t			lock; /* protects all pool lists */
82*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_t			wake_idle;
83*1c60b9acSAndroid Build Coastguard Worker 	struct lws_pool			*pool_list;
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context		*context;
86*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool		*tp_list; /* context list of threadpools */
87*1c60b9acSAndroid Build Coastguard Worker 
88*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task	*task_queue_head;
89*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task	*task_done_head;
90*1c60b9acSAndroid Build Coastguard Worker 
91*1c60b9acSAndroid Build Coastguard Worker 	char				name[32];
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 	int				threads_in_pool;
94*1c60b9acSAndroid Build Coastguard Worker 	int				queue_depth;
95*1c60b9acSAndroid Build Coastguard Worker 	int				done_queue_depth;
96*1c60b9acSAndroid Build Coastguard Worker 	int				max_queue_depth;
97*1c60b9acSAndroid Build Coastguard Worker 	int				running_tasks;
98*1c60b9acSAndroid Build Coastguard Worker 
99*1c60b9acSAndroid Build Coastguard Worker 	unsigned int			destroying:1;
100*1c60b9acSAndroid Build Coastguard Worker };
101*1c60b9acSAndroid Build Coastguard Worker 
102*1c60b9acSAndroid Build Coastguard Worker static int
ms_delta(lws_usec_t now,lws_usec_t then)103*1c60b9acSAndroid Build Coastguard Worker ms_delta(lws_usec_t now, lws_usec_t then)
104*1c60b9acSAndroid Build Coastguard Worker {
105*1c60b9acSAndroid Build Coastguard Worker 	return (int)((now - then) / 1000);
106*1c60b9acSAndroid Build Coastguard Worker }
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker static void
us_accrue(lws_usec_t * acc,lws_usec_t then)109*1c60b9acSAndroid Build Coastguard Worker us_accrue(lws_usec_t *acc, lws_usec_t then)
110*1c60b9acSAndroid Build Coastguard Worker {
111*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t now = lws_now_usecs();
112*1c60b9acSAndroid Build Coastguard Worker 
113*1c60b9acSAndroid Build Coastguard Worker 	*acc += now - then;
114*1c60b9acSAndroid Build Coastguard Worker }
115*1c60b9acSAndroid Build Coastguard Worker 
116*1c60b9acSAndroid Build Coastguard Worker static int
pc_delta(lws_usec_t now,lws_usec_t then,lws_usec_t us)117*1c60b9acSAndroid Build Coastguard Worker pc_delta(lws_usec_t now, lws_usec_t then, lws_usec_t us)
118*1c60b9acSAndroid Build Coastguard Worker {
119*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t delta = (now - then) + 1;
120*1c60b9acSAndroid Build Coastguard Worker 
121*1c60b9acSAndroid Build Coastguard Worker 	return (int)((us * 100) / delta);
122*1c60b9acSAndroid Build Coastguard Worker }
123*1c60b9acSAndroid Build Coastguard Worker 
124*1c60b9acSAndroid Build Coastguard Worker static void
__lws_threadpool_task_dump(struct lws_threadpool_task * task,char * buf,int len)125*1c60b9acSAndroid Build Coastguard Worker __lws_threadpool_task_dump(struct lws_threadpool_task *task, char *buf, int len)
126*1c60b9acSAndroid Build Coastguard Worker {
127*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t now = lws_now_usecs();
128*1c60b9acSAndroid Build Coastguard Worker 	char *end = buf + len - 1;
129*1c60b9acSAndroid Build Coastguard Worker 	int syncms = 0, runms = 0;
130*1c60b9acSAndroid Build Coastguard Worker 
131*1c60b9acSAndroid Build Coastguard Worker 	if (!task->acquired) {
132*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
133*1c60b9acSAndroid Build Coastguard Worker 				    "task: %s, QUEUED queued: %dms",
134*1c60b9acSAndroid Build Coastguard Worker 				    task->name, ms_delta(now, task->created));
135*1c60b9acSAndroid Build Coastguard Worker 
136*1c60b9acSAndroid Build Coastguard Worker 		return;
137*1c60b9acSAndroid Build Coastguard Worker 	}
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 	if (task->acc_running)
140*1c60b9acSAndroid Build Coastguard Worker 		runms = (int)task->acc_running;
141*1c60b9acSAndroid Build Coastguard Worker 
142*1c60b9acSAndroid Build Coastguard Worker 	if (task->acc_syncing)
143*1c60b9acSAndroid Build Coastguard Worker 		syncms = (int)task->acc_syncing;
144*1c60b9acSAndroid Build Coastguard Worker 
145*1c60b9acSAndroid Build Coastguard Worker 	if (!task->done) {
146*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
147*1c60b9acSAndroid Build Coastguard Worker 			"task: %s, ONGOING state %d (%dms) alive: %dms "
148*1c60b9acSAndroid Build Coastguard Worker 			"(queued %dms, acquired: %dms, "
149*1c60b9acSAndroid Build Coastguard Worker 			"run: %d%%, sync: %d%%)", task->name, task->status,
150*1c60b9acSAndroid Build Coastguard Worker 			ms_delta(now, task->entered_state),
151*1c60b9acSAndroid Build Coastguard Worker 			ms_delta(now, task->created),
152*1c60b9acSAndroid Build Coastguard Worker 			ms_delta(task->acquired, task->created),
153*1c60b9acSAndroid Build Coastguard Worker 			ms_delta(now, task->acquired),
154*1c60b9acSAndroid Build Coastguard Worker 			pc_delta(now, task->acquired, runms),
155*1c60b9acSAndroid Build Coastguard Worker 			pc_delta(now, task->acquired, syncms));
156*1c60b9acSAndroid Build Coastguard Worker 
157*1c60b9acSAndroid Build Coastguard Worker 		return;
158*1c60b9acSAndroid Build Coastguard Worker 	}
159*1c60b9acSAndroid Build Coastguard Worker 
160*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
161*1c60b9acSAndroid Build Coastguard Worker 		"task: %s, DONE state %d lived: %dms "
162*1c60b9acSAndroid Build Coastguard Worker 		"(queued %dms, on thread: %dms, "
163*1c60b9acSAndroid Build Coastguard Worker 		"ran: %d%%, synced: %d%%)", task->name, task->status,
164*1c60b9acSAndroid Build Coastguard Worker 		ms_delta(task->done, task->created),
165*1c60b9acSAndroid Build Coastguard Worker 		ms_delta(task->acquired, task->created),
166*1c60b9acSAndroid Build Coastguard Worker 		ms_delta(task->done, task->acquired),
167*1c60b9acSAndroid Build Coastguard Worker 		pc_delta(task->done, task->acquired, runms),
168*1c60b9acSAndroid Build Coastguard Worker 		pc_delta(task->done, task->acquired, syncms));
169*1c60b9acSAndroid Build Coastguard Worker }
170*1c60b9acSAndroid Build Coastguard Worker 
171*1c60b9acSAndroid Build Coastguard Worker void
lws_threadpool_dump(struct lws_threadpool * tp)172*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_dump(struct lws_threadpool *tp)
173*1c60b9acSAndroid Build Coastguard Worker {
174*1c60b9acSAndroid Build Coastguard Worker #if 0
175*1c60b9acSAndroid Build Coastguard Worker 	//defined(_DEBUG)
176*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c;
177*1c60b9acSAndroid Build Coastguard Worker 	char buf[160];
178*1c60b9acSAndroid Build Coastguard Worker 	int n, count;
179*1c60b9acSAndroid Build Coastguard Worker 
180*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
181*1c60b9acSAndroid Build Coastguard Worker 
182*1c60b9acSAndroid Build Coastguard Worker 	lwsl_thread("%s: tp: %s, Queued: %d, Run: %d, Done: %d\n", __func__,
183*1c60b9acSAndroid Build Coastguard Worker 		    tp->name, tp->queue_depth, tp->running_tasks,
184*1c60b9acSAndroid Build Coastguard Worker 		    tp->done_queue_depth);
185*1c60b9acSAndroid Build Coastguard Worker 
186*1c60b9acSAndroid Build Coastguard Worker 	count = 0;
187*1c60b9acSAndroid Build Coastguard Worker 	c = &tp->task_queue_head;
188*1c60b9acSAndroid Build Coastguard Worker 	while (*c) {
189*1c60b9acSAndroid Build Coastguard Worker 		struct lws_threadpool_task *task = *c;
190*1c60b9acSAndroid Build Coastguard Worker 		__lws_threadpool_task_dump(task, buf, sizeof(buf));
191*1c60b9acSAndroid Build Coastguard Worker 		lwsl_thread("  - %s\n", buf);
192*1c60b9acSAndroid Build Coastguard Worker 		count++;
193*1c60b9acSAndroid Build Coastguard Worker 
194*1c60b9acSAndroid Build Coastguard Worker 		c = &(*c)->task_queue_next;
195*1c60b9acSAndroid Build Coastguard Worker 	}
196*1c60b9acSAndroid Build Coastguard Worker 
197*1c60b9acSAndroid Build Coastguard Worker 	if (count != tp->queue_depth)
198*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: tp says queue depth %d, but actually %d\n",
199*1c60b9acSAndroid Build Coastguard Worker 			 __func__, tp->queue_depth, count);
200*1c60b9acSAndroid Build Coastguard Worker 
201*1c60b9acSAndroid Build Coastguard Worker 	count = 0;
202*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < tp->threads_in_pool; n++) {
203*1c60b9acSAndroid Build Coastguard Worker 		struct lws_pool *pool = &tp->pool_list[n];
204*1c60b9acSAndroid Build Coastguard Worker 		struct lws_threadpool_task *task = pool->task;
205*1c60b9acSAndroid Build Coastguard Worker 
206*1c60b9acSAndroid Build Coastguard Worker 		if (task) {
207*1c60b9acSAndroid Build Coastguard Worker 			__lws_threadpool_task_dump(task, buf, sizeof(buf));
208*1c60b9acSAndroid Build Coastguard Worker 			lwsl_thread("  - worker %d: %s\n", n, buf);
209*1c60b9acSAndroid Build Coastguard Worker 			count++;
210*1c60b9acSAndroid Build Coastguard Worker 		}
211*1c60b9acSAndroid Build Coastguard Worker 	}
212*1c60b9acSAndroid Build Coastguard Worker 
213*1c60b9acSAndroid Build Coastguard Worker 	if (count != tp->running_tasks)
214*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: tp says %d running_tasks, but actually %d\n",
215*1c60b9acSAndroid Build Coastguard Worker 			 __func__, tp->running_tasks, count);
216*1c60b9acSAndroid Build Coastguard Worker 
217*1c60b9acSAndroid Build Coastguard Worker 	count = 0;
218*1c60b9acSAndroid Build Coastguard Worker 	c = &tp->task_done_head;
219*1c60b9acSAndroid Build Coastguard Worker 	while (*c) {
220*1c60b9acSAndroid Build Coastguard Worker 		struct lws_threadpool_task *task = *c;
221*1c60b9acSAndroid Build Coastguard Worker 		__lws_threadpool_task_dump(task, buf, sizeof(buf));
222*1c60b9acSAndroid Build Coastguard Worker 		lwsl_thread("  - %s\n", buf);
223*1c60b9acSAndroid Build Coastguard Worker 		count++;
224*1c60b9acSAndroid Build Coastguard Worker 
225*1c60b9acSAndroid Build Coastguard Worker 		c = &(*c)->task_queue_next;
226*1c60b9acSAndroid Build Coastguard Worker 	}
227*1c60b9acSAndroid Build Coastguard Worker 
228*1c60b9acSAndroid Build Coastguard Worker 	if (count != tp->done_queue_depth)
229*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: tp says done_queue_depth %d, but actually %d\n",
230*1c60b9acSAndroid Build Coastguard Worker 			 __func__, tp->done_queue_depth, count);
231*1c60b9acSAndroid Build Coastguard Worker 
232*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&tp->lock); /* --------------- tp unlock */
233*1c60b9acSAndroid Build Coastguard Worker #endif
234*1c60b9acSAndroid Build Coastguard Worker }
235*1c60b9acSAndroid Build Coastguard Worker 
236*1c60b9acSAndroid Build Coastguard Worker static void
state_transition(struct lws_threadpool_task * task,enum lws_threadpool_task_status status)237*1c60b9acSAndroid Build Coastguard Worker state_transition(struct lws_threadpool_task *task,
238*1c60b9acSAndroid Build Coastguard Worker 		 enum lws_threadpool_task_status status)
239*1c60b9acSAndroid Build Coastguard Worker {
240*1c60b9acSAndroid Build Coastguard Worker 	task->entered_state = lws_now_usecs();
241*1c60b9acSAndroid Build Coastguard Worker 	task->status = status;
242*1c60b9acSAndroid Build Coastguard Worker }
243*1c60b9acSAndroid Build Coastguard Worker 
244*1c60b9acSAndroid Build Coastguard Worker static struct lws *
task_to_wsi(struct lws_threadpool_task * task)245*1c60b9acSAndroid Build Coastguard Worker task_to_wsi(struct lws_threadpool_task *task)
246*1c60b9acSAndroid Build Coastguard Worker {
247*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
248*1c60b9acSAndroid Build Coastguard Worker 	if (task->args.ss)
249*1c60b9acSAndroid Build Coastguard Worker 		return task->args.ss->wsi;
250*1c60b9acSAndroid Build Coastguard Worker #endif
251*1c60b9acSAndroid Build Coastguard Worker 	return task->args.wsi;
252*1c60b9acSAndroid Build Coastguard Worker }
253*1c60b9acSAndroid Build Coastguard Worker 
254*1c60b9acSAndroid Build Coastguard Worker static void
lws_threadpool_task_cleanup_destroy(struct lws_threadpool_task * task)255*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_task_cleanup_destroy(struct lws_threadpool_task *task)
256*1c60b9acSAndroid Build Coastguard Worker {
257*1c60b9acSAndroid Build Coastguard Worker 	if (task->args.cleanup)
258*1c60b9acSAndroid Build Coastguard Worker 		task->args.cleanup(task_to_wsi(task), task->args.user);
259*1c60b9acSAndroid Build Coastguard Worker 
260*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&task->list);
261*1c60b9acSAndroid Build Coastguard Worker 
262*1c60b9acSAndroid Build Coastguard Worker 	lwsl_thread("%s: tp %p: cleaned finished task for %s\n",
263*1c60b9acSAndroid Build Coastguard Worker 		    __func__, task->tp, lws_wsi_tag(task_to_wsi(task)));
264*1c60b9acSAndroid Build Coastguard Worker 
265*1c60b9acSAndroid Build Coastguard Worker 	lws_free(task);
266*1c60b9acSAndroid Build Coastguard Worker }
267*1c60b9acSAndroid Build Coastguard Worker 
268*1c60b9acSAndroid Build Coastguard Worker static void
__lws_threadpool_reap(struct lws_threadpool_task * task)269*1c60b9acSAndroid Build Coastguard Worker __lws_threadpool_reap(struct lws_threadpool_task *task)
270*1c60b9acSAndroid Build Coastguard Worker {
271*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c, *t = NULL;
272*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp = task->tp;
273*1c60b9acSAndroid Build Coastguard Worker 
274*1c60b9acSAndroid Build Coastguard Worker 	/* remove the task from the done queue */
275*1c60b9acSAndroid Build Coastguard Worker 
276*1c60b9acSAndroid Build Coastguard Worker 	if (tp) {
277*1c60b9acSAndroid Build Coastguard Worker 		c = &tp->task_done_head;
278*1c60b9acSAndroid Build Coastguard Worker 
279*1c60b9acSAndroid Build Coastguard Worker 		while (*c) {
280*1c60b9acSAndroid Build Coastguard Worker 			if ((*c) == task) {
281*1c60b9acSAndroid Build Coastguard Worker 				t = *c;
282*1c60b9acSAndroid Build Coastguard Worker 				*c = t->task_queue_next;
283*1c60b9acSAndroid Build Coastguard Worker 				t->task_queue_next = NULL;
284*1c60b9acSAndroid Build Coastguard Worker 				tp->done_queue_depth--;
285*1c60b9acSAndroid Build Coastguard Worker 
286*1c60b9acSAndroid Build Coastguard Worker 				lwsl_thread("%s: tp %s: reaped task %s\n", __func__,
287*1c60b9acSAndroid Build Coastguard Worker 					   tp->name, lws_wsi_tag(task_to_wsi(task)));
288*1c60b9acSAndroid Build Coastguard Worker 
289*1c60b9acSAndroid Build Coastguard Worker 				break;
290*1c60b9acSAndroid Build Coastguard Worker 			}
291*1c60b9acSAndroid Build Coastguard Worker 			c = &(*c)->task_queue_next;
292*1c60b9acSAndroid Build Coastguard Worker 		}
293*1c60b9acSAndroid Build Coastguard Worker 
294*1c60b9acSAndroid Build Coastguard Worker 		if (!t) {
295*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: task %p not in done queue\n", __func__, task);
296*1c60b9acSAndroid Build Coastguard Worker 			/*
297*1c60b9acSAndroid Build Coastguard Worker 			 * This shouldn't occur, but in this case not really
298*1c60b9acSAndroid Build Coastguard Worker 			 * safe to assume there's a task to destroy
299*1c60b9acSAndroid Build Coastguard Worker 			 */
300*1c60b9acSAndroid Build Coastguard Worker 			return;
301*1c60b9acSAndroid Build Coastguard Worker 		}
302*1c60b9acSAndroid Build Coastguard Worker 	} else
303*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: task->tp NULL already\n", __func__);
304*1c60b9acSAndroid Build Coastguard Worker 
305*1c60b9acSAndroid Build Coastguard Worker 	/* call the task's cleanup and delete the task itself */
306*1c60b9acSAndroid Build Coastguard Worker 
307*1c60b9acSAndroid Build Coastguard Worker 	lws_threadpool_task_cleanup_destroy(task);
308*1c60b9acSAndroid Build Coastguard Worker }
309*1c60b9acSAndroid Build Coastguard Worker 
310*1c60b9acSAndroid Build Coastguard Worker /*
311*1c60b9acSAndroid Build Coastguard Worker  * this gets called from each tsi service context after the service was
312*1c60b9acSAndroid Build Coastguard Worker  * cancelled... we need to ask for the writable callback from the matching
313*1c60b9acSAndroid Build Coastguard Worker  * tsi context for any wsis bound to a worked thread that need it
314*1c60b9acSAndroid Build Coastguard Worker  */
315*1c60b9acSAndroid Build Coastguard Worker 
316*1c60b9acSAndroid Build Coastguard Worker int
lws_threadpool_tsi_context(struct lws_context * context,int tsi)317*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_tsi_context(struct lws_context *context, int tsi)
318*1c60b9acSAndroid Build Coastguard Worker {
319*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c, *task = NULL;
320*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp;
321*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
322*1c60b9acSAndroid Build Coastguard Worker 
323*1c60b9acSAndroid Build Coastguard Worker 	lws_context_lock(context, __func__);
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 	tp = context->tp_list_head;
326*1c60b9acSAndroid Build Coastguard Worker 	while (tp) {
327*1c60b9acSAndroid Build Coastguard Worker 		int n;
328*1c60b9acSAndroid Build Coastguard Worker 
329*1c60b9acSAndroid Build Coastguard Worker 		/* for the running (syncing...) tasks... */
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker 		for (n = 0; n < tp->threads_in_pool; n++) {
332*1c60b9acSAndroid Build Coastguard Worker 			struct lws_pool *pool = &tp->pool_list[n];
333*1c60b9acSAndroid Build Coastguard Worker 
334*1c60b9acSAndroid Build Coastguard Worker 			task = pool->task;
335*1c60b9acSAndroid Build Coastguard Worker 			if (!task)
336*1c60b9acSAndroid Build Coastguard Worker 				continue;
337*1c60b9acSAndroid Build Coastguard Worker 
338*1c60b9acSAndroid Build Coastguard Worker 			wsi = task_to_wsi(task);
339*1c60b9acSAndroid Build Coastguard Worker 			if (!wsi || wsi->tsi != tsi ||
340*1c60b9acSAndroid Build Coastguard Worker 			    (!task->wanted_writeable_cb &&
341*1c60b9acSAndroid Build Coastguard Worker 			     task->status != LWS_TP_STATUS_SYNCING))
342*1c60b9acSAndroid Build Coastguard Worker 				continue;
343*1c60b9acSAndroid Build Coastguard Worker 
344*1c60b9acSAndroid Build Coastguard Worker 			task->wanted_writeable_cb = 0;
345*1c60b9acSAndroid Build Coastguard Worker 			lws_memory_barrier();
346*1c60b9acSAndroid Build Coastguard Worker 
347*1c60b9acSAndroid Build Coastguard Worker 			/*
348*1c60b9acSAndroid Build Coastguard Worker 			 * finally... we can ask for the callback on
349*1c60b9acSAndroid Build Coastguard Worker 			 * writable from the correct service thread
350*1c60b9acSAndroid Build Coastguard Worker 			 * context
351*1c60b9acSAndroid Build Coastguard Worker 			 */
352*1c60b9acSAndroid Build Coastguard Worker 
353*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
354*1c60b9acSAndroid Build Coastguard Worker 		}
355*1c60b9acSAndroid Build Coastguard Worker 
356*1c60b9acSAndroid Build Coastguard Worker 		/* for the done tasks... */
357*1c60b9acSAndroid Build Coastguard Worker 
358*1c60b9acSAndroid Build Coastguard Worker 		c = &tp->task_done_head;
359*1c60b9acSAndroid Build Coastguard Worker 
360*1c60b9acSAndroid Build Coastguard Worker 		while (*c) {
361*1c60b9acSAndroid Build Coastguard Worker 			task = *c;
362*1c60b9acSAndroid Build Coastguard Worker 			wsi = task_to_wsi(task);
363*1c60b9acSAndroid Build Coastguard Worker 
364*1c60b9acSAndroid Build Coastguard Worker 			if (wsi && wsi->tsi == tsi &&
365*1c60b9acSAndroid Build Coastguard Worker 			    (task->wanted_writeable_cb ||
366*1c60b9acSAndroid Build Coastguard Worker 			     task->status == LWS_TP_STATUS_SYNCING)) {
367*1c60b9acSAndroid Build Coastguard Worker 
368*1c60b9acSAndroid Build Coastguard Worker 				task->wanted_writeable_cb = 0;
369*1c60b9acSAndroid Build Coastguard Worker 				lws_memory_barrier();
370*1c60b9acSAndroid Build Coastguard Worker 
371*1c60b9acSAndroid Build Coastguard Worker 				/*
372*1c60b9acSAndroid Build Coastguard Worker 				 * finally... we can ask for the callback on
373*1c60b9acSAndroid Build Coastguard Worker 				 * writable from the correct service thread
374*1c60b9acSAndroid Build Coastguard Worker 				 * context
375*1c60b9acSAndroid Build Coastguard Worker 				 */
376*1c60b9acSAndroid Build Coastguard Worker 
377*1c60b9acSAndroid Build Coastguard Worker 				lws_callback_on_writable(wsi);
378*1c60b9acSAndroid Build Coastguard Worker 			}
379*1c60b9acSAndroid Build Coastguard Worker 
380*1c60b9acSAndroid Build Coastguard Worker 			c = &task->task_queue_next;
381*1c60b9acSAndroid Build Coastguard Worker 		}
382*1c60b9acSAndroid Build Coastguard Worker 
383*1c60b9acSAndroid Build Coastguard Worker 		tp = tp->tp_list;
384*1c60b9acSAndroid Build Coastguard Worker 	}
385*1c60b9acSAndroid Build Coastguard Worker 
386*1c60b9acSAndroid Build Coastguard Worker 	lws_context_unlock(context);
387*1c60b9acSAndroid Build Coastguard Worker 
388*1c60b9acSAndroid Build Coastguard Worker 	return 0;
389*1c60b9acSAndroid Build Coastguard Worker }
390*1c60b9acSAndroid Build Coastguard Worker 
391*1c60b9acSAndroid Build Coastguard Worker static int
lws_threadpool_worker_sync(struct lws_pool * pool,struct lws_threadpool_task * task)392*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_worker_sync(struct lws_pool *pool,
393*1c60b9acSAndroid Build Coastguard Worker 			   struct lws_threadpool_task *task)
394*1c60b9acSAndroid Build Coastguard Worker {
395*1c60b9acSAndroid Build Coastguard Worker 	enum lws_threadpool_task_status temp;
396*1c60b9acSAndroid Build Coastguard Worker 	struct timespec abstime;
397*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
398*1c60b9acSAndroid Build Coastguard Worker 	int tries = 15;
399*1c60b9acSAndroid Build Coastguard Worker 
400*1c60b9acSAndroid Build Coastguard Worker 	/* block until writable acknowledges */
401*1c60b9acSAndroid Build Coastguard Worker 	lwsl_debug("%s: %p: LWS_TP_RETURN_SYNC in\n", __func__, task);
402*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&pool->lock); /* ======================= pool lock */
403*1c60b9acSAndroid Build Coastguard Worker 
404*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: %s: task %p (%s): syncing with %s\n", __func__,
405*1c60b9acSAndroid Build Coastguard Worker 		    pool->tp->name, task, task->name, lws_wsi_tag(task_to_wsi(task)));
406*1c60b9acSAndroid Build Coastguard Worker 
407*1c60b9acSAndroid Build Coastguard Worker 	temp = task->status;
408*1c60b9acSAndroid Build Coastguard Worker 	state_transition(task, LWS_TP_STATUS_SYNCING);
409*1c60b9acSAndroid Build Coastguard Worker 	while (tries--) {
410*1c60b9acSAndroid Build Coastguard Worker 		wsi = task_to_wsi(task);
411*1c60b9acSAndroid Build Coastguard Worker 
412*1c60b9acSAndroid Build Coastguard Worker 		/*
413*1c60b9acSAndroid Build Coastguard Worker 		 * if the wsi is no longer attached to this task, there is
414*1c60b9acSAndroid Build Coastguard Worker 		 * nothing we can sync to usefully.  Since the work wants to
415*1c60b9acSAndroid Build Coastguard Worker 		 * sync, it means we should react to the situation by telling
416*1c60b9acSAndroid Build Coastguard Worker 		 * the task it can't continue usefully by stopping it.
417*1c60b9acSAndroid Build Coastguard Worker 		 */
418*1c60b9acSAndroid Build Coastguard Worker 
419*1c60b9acSAndroid Build Coastguard Worker 		if (!wsi) {
420*1c60b9acSAndroid Build Coastguard Worker 			lwsl_thread("%s: %s: task %p (%s): No longer bound to any "
421*1c60b9acSAndroid Build Coastguard Worker 				 "wsi to sync to\n", __func__, pool->tp->name,
422*1c60b9acSAndroid Build Coastguard Worker 				 task, task->name);
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker 			state_transition(task, LWS_TP_STATUS_STOPPING);
425*1c60b9acSAndroid Build Coastguard Worker 			goto done;
426*1c60b9acSAndroid Build Coastguard Worker 		}
427*1c60b9acSAndroid Build Coastguard Worker 
428*1c60b9acSAndroid Build Coastguard Worker 		/*
429*1c60b9acSAndroid Build Coastguard Worker 		 * So "tries" times this is the maximum time between SYNC asking
430*1c60b9acSAndroid Build Coastguard Worker 		 * for a callback on writable and actually getting it we are
431*1c60b9acSAndroid Build Coastguard Worker 		 * willing to sit still for.
432*1c60b9acSAndroid Build Coastguard Worker 		 *
433*1c60b9acSAndroid Build Coastguard Worker 		 * If it is exceeded, we will stop the task.
434*1c60b9acSAndroid Build Coastguard Worker 		 */
435*1c60b9acSAndroid Build Coastguard Worker 		abstime.tv_sec = time(NULL) + 3;
436*1c60b9acSAndroid Build Coastguard Worker 		abstime.tv_nsec = 0;
437*1c60b9acSAndroid Build Coastguard Worker 
438*1c60b9acSAndroid Build Coastguard Worker 		task->wanted_writeable_cb = 1;
439*1c60b9acSAndroid Build Coastguard Worker 		lws_memory_barrier();
440*1c60b9acSAndroid Build Coastguard Worker 
441*1c60b9acSAndroid Build Coastguard Worker 		/*
442*1c60b9acSAndroid Build Coastguard Worker 		 * This will cause lws_threadpool_tsi_context() to get called
443*1c60b9acSAndroid Build Coastguard Worker 		 * from each tsi service context, where we can safely ask for
444*1c60b9acSAndroid Build Coastguard Worker 		 * a callback on writeable on the wsi we are associated with.
445*1c60b9acSAndroid Build Coastguard Worker 		 */
446*1c60b9acSAndroid Build Coastguard Worker 		lws_cancel_service(lws_get_context(wsi));
447*1c60b9acSAndroid Build Coastguard Worker 
448*1c60b9acSAndroid Build Coastguard Worker 		/*
449*1c60b9acSAndroid Build Coastguard Worker 		 * so the danger here is that we asked for a writable callback
450*1c60b9acSAndroid Build Coastguard Worker 		 * on the wsi, but for whatever reason, we are never going to
451*1c60b9acSAndroid Build Coastguard Worker 		 * get one.  To avoid deadlocking forever, we allow a set time
452*1c60b9acSAndroid Build Coastguard Worker 		 * for the sync to happen naturally, otherwise the cond wait
453*1c60b9acSAndroid Build Coastguard Worker 		 * times out and we stop the task.
454*1c60b9acSAndroid Build Coastguard Worker 		 */
455*1c60b9acSAndroid Build Coastguard Worker 
456*1c60b9acSAndroid Build Coastguard Worker 		if (pthread_cond_timedwait(&task->wake_idle, &pool->lock,
457*1c60b9acSAndroid Build Coastguard Worker 					   &abstime) == ETIMEDOUT) {
458*1c60b9acSAndroid Build Coastguard Worker 			task->late_sync_retries++;
459*1c60b9acSAndroid Build Coastguard Worker 			if (!tries) {
460*1c60b9acSAndroid Build Coastguard Worker 				lwsl_err("%s: %s: task %p (%s): SYNC timed out "
461*1c60b9acSAndroid Build Coastguard Worker 					 "(associated %s)\n",
462*1c60b9acSAndroid Build Coastguard Worker 					 __func__, pool->tp->name, task,
463*1c60b9acSAndroid Build Coastguard Worker 					 task->name, lws_wsi_tag(task_to_wsi(task)));
464*1c60b9acSAndroid Build Coastguard Worker 
465*1c60b9acSAndroid Build Coastguard Worker 				pthread_mutex_unlock(&pool->lock); /* ----------------- - pool unlock */
466*1c60b9acSAndroid Build Coastguard Worker 				lws_threadpool_dequeue_task(task);
467*1c60b9acSAndroid Build Coastguard Worker 				return 1; /* destroyed task */
468*1c60b9acSAndroid Build Coastguard Worker 			}
469*1c60b9acSAndroid Build Coastguard Worker 
470*1c60b9acSAndroid Build Coastguard Worker 			continue;
471*1c60b9acSAndroid Build Coastguard Worker 		} else
472*1c60b9acSAndroid Build Coastguard Worker 			break;
473*1c60b9acSAndroid Build Coastguard Worker 	}
474*1c60b9acSAndroid Build Coastguard Worker 
475*1c60b9acSAndroid Build Coastguard Worker 	if (task->status == LWS_TP_STATUS_SYNCING)
476*1c60b9acSAndroid Build Coastguard Worker 		state_transition(task, temp);
477*1c60b9acSAndroid Build Coastguard Worker 
478*1c60b9acSAndroid Build Coastguard Worker 	lwsl_debug("%s: %p: LWS_TP_RETURN_SYNC out\n", __func__, task);
479*1c60b9acSAndroid Build Coastguard Worker 
480*1c60b9acSAndroid Build Coastguard Worker done:
481*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&pool->lock); /* ----------------- - pool unlock */
482*1c60b9acSAndroid Build Coastguard Worker 
483*1c60b9acSAndroid Build Coastguard Worker 	return 0;
484*1c60b9acSAndroid Build Coastguard Worker }
485*1c60b9acSAndroid Build Coastguard Worker 
486*1c60b9acSAndroid Build Coastguard Worker #if !defined(WIN32)
487*1c60b9acSAndroid Build Coastguard Worker static int dummy;
488*1c60b9acSAndroid Build Coastguard Worker #endif
489*1c60b9acSAndroid Build Coastguard Worker 
490*1c60b9acSAndroid Build Coastguard Worker static void *
lws_threadpool_worker(void * d)491*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_worker(void *d)
492*1c60b9acSAndroid Build Coastguard Worker {
493*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c, **c2, *task;
494*1c60b9acSAndroid Build Coastguard Worker 	struct lws_pool *pool = d;
495*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp = pool->tp;
496*1c60b9acSAndroid Build Coastguard Worker 	char buf[160];
497*1c60b9acSAndroid Build Coastguard Worker 
498*1c60b9acSAndroid Build Coastguard Worker 	while (!tp->destroying) {
499*1c60b9acSAndroid Build Coastguard Worker 
500*1c60b9acSAndroid Build Coastguard Worker 		/* we have no running task... wait and get one from the queue */
501*1c60b9acSAndroid Build Coastguard Worker 
502*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&tp->lock); /* =================== tp lock */
503*1c60b9acSAndroid Build Coastguard Worker 
504*1c60b9acSAndroid Build Coastguard Worker 		/*
505*1c60b9acSAndroid Build Coastguard Worker 		 * if there's no task already waiting in the queue, wait for
506*1c60b9acSAndroid Build Coastguard Worker 		 * the wake_idle condition to signal us that might have changed
507*1c60b9acSAndroid Build Coastguard Worker 		 */
508*1c60b9acSAndroid Build Coastguard Worker 		while (!tp->task_queue_head && !tp->destroying)
509*1c60b9acSAndroid Build Coastguard Worker 			pthread_cond_wait(&tp->wake_idle, &tp->lock);
510*1c60b9acSAndroid Build Coastguard Worker 
511*1c60b9acSAndroid Build Coastguard Worker 		if (tp->destroying) {
512*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: bailing\n", __func__);
513*1c60b9acSAndroid Build Coastguard Worker 			goto doneski;
514*1c60b9acSAndroid Build Coastguard Worker 		}
515*1c60b9acSAndroid Build Coastguard Worker 
516*1c60b9acSAndroid Build Coastguard Worker 		c = &tp->task_queue_head;
517*1c60b9acSAndroid Build Coastguard Worker 		c2 = NULL;
518*1c60b9acSAndroid Build Coastguard Worker 		task = NULL;
519*1c60b9acSAndroid Build Coastguard Worker 		pool->task = NULL;
520*1c60b9acSAndroid Build Coastguard Worker 
521*1c60b9acSAndroid Build Coastguard Worker 		/* look at the queue tail */
522*1c60b9acSAndroid Build Coastguard Worker 		while (*c) {
523*1c60b9acSAndroid Build Coastguard Worker 			c2 = c;
524*1c60b9acSAndroid Build Coastguard Worker 			c = &(*c)->task_queue_next;
525*1c60b9acSAndroid Build Coastguard Worker 		}
526*1c60b9acSAndroid Build Coastguard Worker 
527*1c60b9acSAndroid Build Coastguard Worker 		/* is there a task at the queue tail? */
528*1c60b9acSAndroid Build Coastguard Worker 		if (c2 && *c2) {
529*1c60b9acSAndroid Build Coastguard Worker 			pool->task = task = *c2;
530*1c60b9acSAndroid Build Coastguard Worker 			task->acquired = pool->acquired = lws_now_usecs();
531*1c60b9acSAndroid Build Coastguard Worker 			/* remove it from the queue */
532*1c60b9acSAndroid Build Coastguard Worker 			*c2 = task->task_queue_next;
533*1c60b9acSAndroid Build Coastguard Worker 			task->task_queue_next = NULL;
534*1c60b9acSAndroid Build Coastguard Worker 			tp->queue_depth--;
535*1c60b9acSAndroid Build Coastguard Worker 			/* mark it as running */
536*1c60b9acSAndroid Build Coastguard Worker 			state_transition(task, LWS_TP_STATUS_RUNNING);
537*1c60b9acSAndroid Build Coastguard Worker 		}
538*1c60b9acSAndroid Build Coastguard Worker 
539*1c60b9acSAndroid Build Coastguard Worker 		/* someone else got it first... wait and try again */
540*1c60b9acSAndroid Build Coastguard Worker 		if (!task) {
541*1c60b9acSAndroid Build Coastguard Worker 			pthread_mutex_unlock(&tp->lock);  /* ------ tp unlock */
542*1c60b9acSAndroid Build Coastguard Worker 			continue;
543*1c60b9acSAndroid Build Coastguard Worker 		}
544*1c60b9acSAndroid Build Coastguard Worker 
545*1c60b9acSAndroid Build Coastguard Worker 		task->wanted_writeable_cb = 0;
546*1c60b9acSAndroid Build Coastguard Worker 
547*1c60b9acSAndroid Build Coastguard Worker 		/* we have acquired a new task */
548*1c60b9acSAndroid Build Coastguard Worker 
549*1c60b9acSAndroid Build Coastguard Worker 		__lws_threadpool_task_dump(task, buf, sizeof(buf));
550*1c60b9acSAndroid Build Coastguard Worker 
551*1c60b9acSAndroid Build Coastguard Worker 		lwsl_thread("%s: %s: worker %d ACQUIRING: %s\n",
552*1c60b9acSAndroid Build Coastguard Worker 			    __func__, tp->name, pool->worker_index, buf);
553*1c60b9acSAndroid Build Coastguard Worker 		tp->running_tasks++;
554*1c60b9acSAndroid Build Coastguard Worker 
555*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&tp->lock); /* --------------- tp unlock */
556*1c60b9acSAndroid Build Coastguard Worker 
557*1c60b9acSAndroid Build Coastguard Worker 		/*
558*1c60b9acSAndroid Build Coastguard Worker 		 * 1) The task can return with LWS_TP_RETURN_CHECKING_IN to
559*1c60b9acSAndroid Build Coastguard Worker 		 * "resurface" periodically, and get called again with
560*1c60b9acSAndroid Build Coastguard Worker 		 * cont = 1 immediately to indicate it is picking up where it
561*1c60b9acSAndroid Build Coastguard Worker 		 * left off if the task is not being "stopped".
562*1c60b9acSAndroid Build Coastguard Worker 		 *
563*1c60b9acSAndroid Build Coastguard Worker 		 * This allows long tasks to respond to requests to stop in
564*1c60b9acSAndroid Build Coastguard Worker 		 * a clean and opaque way.
565*1c60b9acSAndroid Build Coastguard Worker 		 *
566*1c60b9acSAndroid Build Coastguard Worker 		 * 2) The task can return with LWS_TP_RETURN_SYNC to register
567*1c60b9acSAndroid Build Coastguard Worker 		 * a "callback on writable" request on the service thread and
568*1c60b9acSAndroid Build Coastguard Worker 		 * block until it hears back from the WRITABLE handler.
569*1c60b9acSAndroid Build Coastguard Worker 		 *
570*1c60b9acSAndroid Build Coastguard Worker 		 * This allows the work on the thread to be synchronized to the
571*1c60b9acSAndroid Build Coastguard Worker 		 * previous work being dispatched cleanly.
572*1c60b9acSAndroid Build Coastguard Worker 		 *
573*1c60b9acSAndroid Build Coastguard Worker 		 * 3) The task can return with LWS_TP_RETURN_FINISHED to
574*1c60b9acSAndroid Build Coastguard Worker 		 * indicate its work is completed nicely.
575*1c60b9acSAndroid Build Coastguard Worker 		 *
576*1c60b9acSAndroid Build Coastguard Worker 		 * 4) The task can return with LWS_TP_RETURN_STOPPED to indicate
577*1c60b9acSAndroid Build Coastguard Worker 		 * it stopped and cleaned up after incomplete work.
578*1c60b9acSAndroid Build Coastguard Worker 		 */
579*1c60b9acSAndroid Build Coastguard Worker 
580*1c60b9acSAndroid Build Coastguard Worker 		do {
581*1c60b9acSAndroid Build Coastguard Worker 			lws_usec_t then;
582*1c60b9acSAndroid Build Coastguard Worker 			int n;
583*1c60b9acSAndroid Build Coastguard Worker 
584*1c60b9acSAndroid Build Coastguard Worker 			if (tp->destroying || !task_to_wsi(task)) {
585*1c60b9acSAndroid Build Coastguard Worker 				lwsl_info("%s: stopping on wsi gone\n", __func__);
586*1c60b9acSAndroid Build Coastguard Worker 				state_transition(task, LWS_TP_STATUS_STOPPING);
587*1c60b9acSAndroid Build Coastguard Worker 			}
588*1c60b9acSAndroid Build Coastguard Worker 
589*1c60b9acSAndroid Build Coastguard Worker 			then = lws_now_usecs();
590*1c60b9acSAndroid Build Coastguard Worker 			n = (int)task->args.task(task->args.user, task->status);
591*1c60b9acSAndroid Build Coastguard Worker 			lwsl_debug("   %d, status %d\n", n, task->status);
592*1c60b9acSAndroid Build Coastguard Worker 			us_accrue(&task->acc_running, then);
593*1c60b9acSAndroid Build Coastguard Worker 			if (n & LWS_TP_RETURN_FLAG_OUTLIVE)
594*1c60b9acSAndroid Build Coastguard Worker 				task->outlive = 1;
595*1c60b9acSAndroid Build Coastguard Worker 			switch (n & 7) {
596*1c60b9acSAndroid Build Coastguard Worker 			case LWS_TP_RETURN_CHECKING_IN:
597*1c60b9acSAndroid Build Coastguard Worker 				/* if not destroying the tp, continue */
598*1c60b9acSAndroid Build Coastguard Worker 				break;
599*1c60b9acSAndroid Build Coastguard Worker 			case LWS_TP_RETURN_SYNC:
600*1c60b9acSAndroid Build Coastguard Worker 				if (!task_to_wsi(task)) {
601*1c60b9acSAndroid Build Coastguard Worker 					lwsl_debug("%s: task that wants to "
602*1c60b9acSAndroid Build Coastguard Worker 						    "outlive lost wsi asked "
603*1c60b9acSAndroid Build Coastguard Worker 						    "to sync: bypassed\n",
604*1c60b9acSAndroid Build Coastguard Worker 						    __func__);
605*1c60b9acSAndroid Build Coastguard Worker 					break;
606*1c60b9acSAndroid Build Coastguard Worker 				}
607*1c60b9acSAndroid Build Coastguard Worker 				/* block until writable acknowledges */
608*1c60b9acSAndroid Build Coastguard Worker 				then = lws_now_usecs();
609*1c60b9acSAndroid Build Coastguard Worker 				if (lws_threadpool_worker_sync(pool, task)) {
610*1c60b9acSAndroid Build Coastguard Worker 					lwsl_notice("%s: Sync failed\n", __func__);
611*1c60b9acSAndroid Build Coastguard Worker 					goto doneski;
612*1c60b9acSAndroid Build Coastguard Worker 				}
613*1c60b9acSAndroid Build Coastguard Worker 				us_accrue(&task->acc_syncing, then);
614*1c60b9acSAndroid Build Coastguard Worker 				break;
615*1c60b9acSAndroid Build Coastguard Worker 			case LWS_TP_RETURN_FINISHED:
616*1c60b9acSAndroid Build Coastguard Worker 				state_transition(task, LWS_TP_STATUS_FINISHED);
617*1c60b9acSAndroid Build Coastguard Worker 				break;
618*1c60b9acSAndroid Build Coastguard Worker 			case LWS_TP_RETURN_STOPPED:
619*1c60b9acSAndroid Build Coastguard Worker 				state_transition(task, LWS_TP_STATUS_STOPPED);
620*1c60b9acSAndroid Build Coastguard Worker 				break;
621*1c60b9acSAndroid Build Coastguard Worker 			}
622*1c60b9acSAndroid Build Coastguard Worker 		} while (task->status == LWS_TP_STATUS_RUNNING);
623*1c60b9acSAndroid Build Coastguard Worker 
624*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&tp->lock); /* =================== tp lock */
625*1c60b9acSAndroid Build Coastguard Worker 
626*1c60b9acSAndroid Build Coastguard Worker 		tp->running_tasks--;
627*1c60b9acSAndroid Build Coastguard Worker 
628*1c60b9acSAndroid Build Coastguard Worker 		if (pool->task->status == LWS_TP_STATUS_STOPPING)
629*1c60b9acSAndroid Build Coastguard Worker 			state_transition(task, LWS_TP_STATUS_STOPPED);
630*1c60b9acSAndroid Build Coastguard Worker 
631*1c60b9acSAndroid Build Coastguard Worker 		/* move the task to the done queue */
632*1c60b9acSAndroid Build Coastguard Worker 
633*1c60b9acSAndroid Build Coastguard Worker 		pool->task->task_queue_next = tp->task_done_head;
634*1c60b9acSAndroid Build Coastguard Worker 		tp->task_done_head = task;
635*1c60b9acSAndroid Build Coastguard Worker 		tp->done_queue_depth++;
636*1c60b9acSAndroid Build Coastguard Worker 		pool->task->done = lws_now_usecs();
637*1c60b9acSAndroid Build Coastguard Worker 
638*1c60b9acSAndroid Build Coastguard Worker 		if (!pool->task->args.wsi &&
639*1c60b9acSAndroid Build Coastguard Worker 		    (pool->task->status == LWS_TP_STATUS_STOPPED ||
640*1c60b9acSAndroid Build Coastguard Worker 		     pool->task->status == LWS_TP_STATUS_FINISHED)) {
641*1c60b9acSAndroid Build Coastguard Worker 
642*1c60b9acSAndroid Build Coastguard Worker 			__lws_threadpool_task_dump(pool->task, buf, sizeof(buf));
643*1c60b9acSAndroid Build Coastguard Worker 			lwsl_thread("%s: %s: worker %d REAPING: %s\n",
644*1c60b9acSAndroid Build Coastguard Worker 				    __func__, tp->name, pool->worker_index,
645*1c60b9acSAndroid Build Coastguard Worker 				    buf);
646*1c60b9acSAndroid Build Coastguard Worker 
647*1c60b9acSAndroid Build Coastguard Worker 			/*
648*1c60b9acSAndroid Build Coastguard Worker 			 * there is no longer any wsi attached, so nothing is
649*1c60b9acSAndroid Build Coastguard Worker 			 * going to take care of reaping us.  So we must take
650*1c60b9acSAndroid Build Coastguard Worker 			 * care of it ourselves.
651*1c60b9acSAndroid Build Coastguard Worker 			 */
652*1c60b9acSAndroid Build Coastguard Worker 			__lws_threadpool_reap(pool->task);
653*1c60b9acSAndroid Build Coastguard Worker 		} else {
654*1c60b9acSAndroid Build Coastguard Worker 
655*1c60b9acSAndroid Build Coastguard Worker 			__lws_threadpool_task_dump(pool->task, buf, sizeof(buf));
656*1c60b9acSAndroid Build Coastguard Worker 			lwsl_thread("%s: %s: worker %d DONE: %s\n",
657*1c60b9acSAndroid Build Coastguard Worker 				    __func__, tp->name, pool->worker_index,
658*1c60b9acSAndroid Build Coastguard Worker 				    buf);
659*1c60b9acSAndroid Build Coastguard Worker 
660*1c60b9acSAndroid Build Coastguard Worker 			/* signal the associated wsi to take a fresh look at
661*1c60b9acSAndroid Build Coastguard Worker 			 * task status */
662*1c60b9acSAndroid Build Coastguard Worker 
663*1c60b9acSAndroid Build Coastguard Worker 			if (task_to_wsi(pool->task)) {
664*1c60b9acSAndroid Build Coastguard Worker 				task->wanted_writeable_cb = 1;
665*1c60b9acSAndroid Build Coastguard Worker 
666*1c60b9acSAndroid Build Coastguard Worker 				lws_cancel_service(
667*1c60b9acSAndroid Build Coastguard Worker 					lws_get_context(task_to_wsi(pool->task)));
668*1c60b9acSAndroid Build Coastguard Worker 			}
669*1c60b9acSAndroid Build Coastguard Worker 		}
670*1c60b9acSAndroid Build Coastguard Worker 
671*1c60b9acSAndroid Build Coastguard Worker doneski:
672*1c60b9acSAndroid Build Coastguard Worker 		pool->task = NULL;
673*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&tp->lock); /* --------------- tp unlock */
674*1c60b9acSAndroid Build Coastguard Worker 	}
675*1c60b9acSAndroid Build Coastguard Worker 
676*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: Exiting\n", __func__);
677*1c60b9acSAndroid Build Coastguard Worker 
678*1c60b9acSAndroid Build Coastguard Worker 	/* threadpool is being destroyed */
679*1c60b9acSAndroid Build Coastguard Worker #if !defined(WIN32)
680*1c60b9acSAndroid Build Coastguard Worker 	pthread_exit(&dummy);
681*1c60b9acSAndroid Build Coastguard Worker #endif
682*1c60b9acSAndroid Build Coastguard Worker 
683*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
684*1c60b9acSAndroid Build Coastguard Worker }
685*1c60b9acSAndroid Build Coastguard Worker 
686*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool *
lws_threadpool_create(struct lws_context * context,const struct lws_threadpool_create_args * args,const char * format,...)687*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_create(struct lws_context *context,
688*1c60b9acSAndroid Build Coastguard Worker 		      const struct lws_threadpool_create_args *args,
689*1c60b9acSAndroid Build Coastguard Worker 		      const char *format, ...)
690*1c60b9acSAndroid Build Coastguard Worker {
691*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp;
692*1c60b9acSAndroid Build Coastguard Worker 	va_list ap;
693*1c60b9acSAndroid Build Coastguard Worker 	int n;
694*1c60b9acSAndroid Build Coastguard Worker 
695*1c60b9acSAndroid Build Coastguard Worker 	tp = lws_malloc(sizeof(*tp) + (sizeof(struct lws_pool) * (unsigned int)args->threads),
696*1c60b9acSAndroid Build Coastguard Worker 			"threadpool alloc");
697*1c60b9acSAndroid Build Coastguard Worker 	if (!tp)
698*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
699*1c60b9acSAndroid Build Coastguard Worker 
700*1c60b9acSAndroid Build Coastguard Worker 	memset(tp, 0, sizeof(*tp) + (sizeof(struct lws_pool) * (unsigned int)args->threads));
701*1c60b9acSAndroid Build Coastguard Worker 	tp->pool_list = (struct lws_pool *)(tp + 1);
702*1c60b9acSAndroid Build Coastguard Worker 	tp->max_queue_depth = args->max_queue_depth;
703*1c60b9acSAndroid Build Coastguard Worker 
704*1c60b9acSAndroid Build Coastguard Worker 	va_start(ap, format);
705*1c60b9acSAndroid Build Coastguard Worker 	n = vsnprintf(tp->name, sizeof(tp->name) - 1, format, ap);
706*1c60b9acSAndroid Build Coastguard Worker 	va_end(ap);
707*1c60b9acSAndroid Build Coastguard Worker 
708*1c60b9acSAndroid Build Coastguard Worker 	lws_context_lock(context, __func__);
709*1c60b9acSAndroid Build Coastguard Worker 
710*1c60b9acSAndroid Build Coastguard Worker 	tp->context = context;
711*1c60b9acSAndroid Build Coastguard Worker 	tp->tp_list = context->tp_list_head;
712*1c60b9acSAndroid Build Coastguard Worker 	context->tp_list_head = tp;
713*1c60b9acSAndroid Build Coastguard Worker 
714*1c60b9acSAndroid Build Coastguard Worker 	lws_context_unlock(context);
715*1c60b9acSAndroid Build Coastguard Worker 
716*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_init(&tp->lock, NULL);
717*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_init(&tp->wake_idle, NULL);
718*1c60b9acSAndroid Build Coastguard Worker 
719*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < args->threads; n++) {
720*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_HAS_PTHREAD_SETNAME_NP)
721*1c60b9acSAndroid Build Coastguard Worker 		char name[16];
722*1c60b9acSAndroid Build Coastguard Worker #endif
723*1c60b9acSAndroid Build Coastguard Worker 		tp->pool_list[n].tp = tp;
724*1c60b9acSAndroid Build Coastguard Worker 		tp->pool_list[n].worker_index = n;
725*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_init(&tp->pool_list[n].lock, NULL);
726*1c60b9acSAndroid Build Coastguard Worker 		if (pthread_create(&tp->pool_list[n].thread, NULL,
727*1c60b9acSAndroid Build Coastguard Worker 				   lws_threadpool_worker, &tp->pool_list[n])) {
728*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("thread creation failed\n");
729*1c60b9acSAndroid Build Coastguard Worker 		} else {
730*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_HAS_PTHREAD_SETNAME_NP)
731*1c60b9acSAndroid Build Coastguard Worker 			lws_snprintf(name, sizeof(name), "%s-%d", tp->name, n);
732*1c60b9acSAndroid Build Coastguard Worker 			pthread_setname_np(tp->pool_list[n].thread, name);
733*1c60b9acSAndroid Build Coastguard Worker #endif
734*1c60b9acSAndroid Build Coastguard Worker 			tp->threads_in_pool++;
735*1c60b9acSAndroid Build Coastguard Worker 		}
736*1c60b9acSAndroid Build Coastguard Worker 	}
737*1c60b9acSAndroid Build Coastguard Worker 
738*1c60b9acSAndroid Build Coastguard Worker 	return tp;
739*1c60b9acSAndroid Build Coastguard Worker }
740*1c60b9acSAndroid Build Coastguard Worker 
741*1c60b9acSAndroid Build Coastguard Worker void
lws_threadpool_finish(struct lws_threadpool * tp)742*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_finish(struct lws_threadpool *tp)
743*1c60b9acSAndroid Build Coastguard Worker {
744*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c, *task;
745*1c60b9acSAndroid Build Coastguard Worker 
746*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
747*1c60b9acSAndroid Build Coastguard Worker 
748*1c60b9acSAndroid Build Coastguard Worker 	/* nothing new can start, running jobs will abort as STOPPED and the
749*1c60b9acSAndroid Build Coastguard Worker 	 * pool threads will exit ASAP (they are joined in destroy) */
750*1c60b9acSAndroid Build Coastguard Worker 	tp->destroying = 1;
751*1c60b9acSAndroid Build Coastguard Worker 
752*1c60b9acSAndroid Build Coastguard Worker 	/* stop everyone in the pending queue and move to the done queue */
753*1c60b9acSAndroid Build Coastguard Worker 
754*1c60b9acSAndroid Build Coastguard Worker 	c = &tp->task_queue_head;
755*1c60b9acSAndroid Build Coastguard Worker 	while (*c) {
756*1c60b9acSAndroid Build Coastguard Worker 		task = *c;
757*1c60b9acSAndroid Build Coastguard Worker 		*c = task->task_queue_next;
758*1c60b9acSAndroid Build Coastguard Worker 		task->task_queue_next = tp->task_done_head;
759*1c60b9acSAndroid Build Coastguard Worker 		tp->task_done_head = task;
760*1c60b9acSAndroid Build Coastguard Worker 		state_transition(task, LWS_TP_STATUS_STOPPED);
761*1c60b9acSAndroid Build Coastguard Worker 		tp->queue_depth--;
762*1c60b9acSAndroid Build Coastguard Worker 		tp->done_queue_depth++;
763*1c60b9acSAndroid Build Coastguard Worker 		task->done = lws_now_usecs();
764*1c60b9acSAndroid Build Coastguard Worker 
765*1c60b9acSAndroid Build Coastguard Worker 		c = &task->task_queue_next;
766*1c60b9acSAndroid Build Coastguard Worker 	}
767*1c60b9acSAndroid Build Coastguard Worker 
768*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_broadcast(&tp->wake_idle);
769*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
770*1c60b9acSAndroid Build Coastguard Worker }
771*1c60b9acSAndroid Build Coastguard Worker 
772*1c60b9acSAndroid Build Coastguard Worker void
lws_threadpool_destroy(struct lws_threadpool * tp)773*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_destroy(struct lws_threadpool *tp)
774*1c60b9acSAndroid Build Coastguard Worker {
775*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task *task, *next;
776*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool **ptp;
777*1c60b9acSAndroid Build Coastguard Worker 	void *retval;
778*1c60b9acSAndroid Build Coastguard Worker 	int n;
779*1c60b9acSAndroid Build Coastguard Worker 
780*1c60b9acSAndroid Build Coastguard Worker 	/* remove us from the context list of threadpools */
781*1c60b9acSAndroid Build Coastguard Worker 
782*1c60b9acSAndroid Build Coastguard Worker 	lws_context_lock(tp->context, __func__);
783*1c60b9acSAndroid Build Coastguard Worker 	ptp = &tp->context->tp_list_head;
784*1c60b9acSAndroid Build Coastguard Worker 
785*1c60b9acSAndroid Build Coastguard Worker 	while (*ptp) {
786*1c60b9acSAndroid Build Coastguard Worker 		if (*ptp == tp) {
787*1c60b9acSAndroid Build Coastguard Worker 			*ptp = tp->tp_list;
788*1c60b9acSAndroid Build Coastguard Worker 			break;
789*1c60b9acSAndroid Build Coastguard Worker 		}
790*1c60b9acSAndroid Build Coastguard Worker 		ptp = &(*ptp)->tp_list;
791*1c60b9acSAndroid Build Coastguard Worker 	}
792*1c60b9acSAndroid Build Coastguard Worker 
793*1c60b9acSAndroid Build Coastguard Worker 	lws_context_unlock(tp->context);
794*1c60b9acSAndroid Build Coastguard Worker 
795*1c60b9acSAndroid Build Coastguard Worker 	/*
796*1c60b9acSAndroid Build Coastguard Worker 	 * Wake up the threadpool guys and tell them to exit
797*1c60b9acSAndroid Build Coastguard Worker 	 */
798*1c60b9acSAndroid Build Coastguard Worker 
799*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
800*1c60b9acSAndroid Build Coastguard Worker 	tp->destroying = 1;
801*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_broadcast(&tp->wake_idle);
802*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
803*1c60b9acSAndroid Build Coastguard Worker 
804*1c60b9acSAndroid Build Coastguard Worker 	lws_threadpool_dump(tp);
805*1c60b9acSAndroid Build Coastguard Worker 
806*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: waiting for threads to rejoin\n", __func__);
807*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
808*1c60b9acSAndroid Build Coastguard Worker 	Sleep(1000);
809*1c60b9acSAndroid Build Coastguard Worker #endif
810*1c60b9acSAndroid Build Coastguard Worker 
811*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < tp->threads_in_pool; n++) {
812*1c60b9acSAndroid Build Coastguard Worker 		task = tp->pool_list[n].task;
813*1c60b9acSAndroid Build Coastguard Worker 
814*1c60b9acSAndroid Build Coastguard Worker 		pthread_join(tp->pool_list[n].thread, &retval);
815*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_destroy(&tp->pool_list[n].lock);
816*1c60b9acSAndroid Build Coastguard Worker 	}
817*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: all threadpools exited\n", __func__);
818*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
819*1c60b9acSAndroid Build Coastguard Worker 	Sleep(1000);
820*1c60b9acSAndroid Build Coastguard Worker #endif
821*1c60b9acSAndroid Build Coastguard Worker 
822*1c60b9acSAndroid Build Coastguard Worker 	task = tp->task_done_head;
823*1c60b9acSAndroid Build Coastguard Worker 	while (task) {
824*1c60b9acSAndroid Build Coastguard Worker 		next = task->task_queue_next;
825*1c60b9acSAndroid Build Coastguard Worker 		lws_threadpool_task_cleanup_destroy(task);
826*1c60b9acSAndroid Build Coastguard Worker 		tp->done_queue_depth--;
827*1c60b9acSAndroid Build Coastguard Worker 		task = next;
828*1c60b9acSAndroid Build Coastguard Worker 	}
829*1c60b9acSAndroid Build Coastguard Worker 
830*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_destroy(&tp->lock);
831*1c60b9acSAndroid Build Coastguard Worker 
832*1c60b9acSAndroid Build Coastguard Worker 	memset(tp, 0xdd, sizeof(*tp));
833*1c60b9acSAndroid Build Coastguard Worker 	lws_free(tp);
834*1c60b9acSAndroid Build Coastguard Worker }
835*1c60b9acSAndroid Build Coastguard Worker 
836*1c60b9acSAndroid Build Coastguard Worker /*
837*1c60b9acSAndroid Build Coastguard Worker  * We want to stop and destroy the tasks and related priv.
838*1c60b9acSAndroid Build Coastguard Worker  */
839*1c60b9acSAndroid Build Coastguard Worker 
840*1c60b9acSAndroid Build Coastguard Worker int
lws_threadpool_dequeue_task(struct lws_threadpool_task * task)841*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_dequeue_task(struct lws_threadpool_task *task)
842*1c60b9acSAndroid Build Coastguard Worker {
843*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp;
844*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task **c;
845*1c60b9acSAndroid Build Coastguard Worker 	int n;
846*1c60b9acSAndroid Build Coastguard Worker 
847*1c60b9acSAndroid Build Coastguard Worker 	tp = task->tp;
848*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
849*1c60b9acSAndroid Build Coastguard Worker 
850*1c60b9acSAndroid Build Coastguard Worker 	if (task->outlive && !tp->destroying) {
851*1c60b9acSAndroid Build Coastguard Worker 
852*1c60b9acSAndroid Build Coastguard Worker 		/* disconnect from wsi, and wsi from task */
853*1c60b9acSAndroid Build Coastguard Worker 
854*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&task->list);
855*1c60b9acSAndroid Build Coastguard Worker 		task->args.wsi = NULL;
856*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
857*1c60b9acSAndroid Build Coastguard Worker 		task->args.ss = NULL;
858*1c60b9acSAndroid Build Coastguard Worker #endif
859*1c60b9acSAndroid Build Coastguard Worker 
860*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
861*1c60b9acSAndroid Build Coastguard Worker 	}
862*1c60b9acSAndroid Build Coastguard Worker 
863*1c60b9acSAndroid Build Coastguard Worker 
864*1c60b9acSAndroid Build Coastguard Worker 	c = &tp->task_queue_head;
865*1c60b9acSAndroid Build Coastguard Worker 
866*1c60b9acSAndroid Build Coastguard Worker 	/* is he queued waiting for a chance to run?  Mark him as stopped and
867*1c60b9acSAndroid Build Coastguard Worker 	 * move him on to the done queue */
868*1c60b9acSAndroid Build Coastguard Worker 
869*1c60b9acSAndroid Build Coastguard Worker 	while (*c) {
870*1c60b9acSAndroid Build Coastguard Worker 		if ((*c) == task) {
871*1c60b9acSAndroid Build Coastguard Worker 			*c = task->task_queue_next;
872*1c60b9acSAndroid Build Coastguard Worker 			task->task_queue_next = tp->task_done_head;
873*1c60b9acSAndroid Build Coastguard Worker 			tp->task_done_head = task;
874*1c60b9acSAndroid Build Coastguard Worker 			state_transition(task, LWS_TP_STATUS_STOPPED);
875*1c60b9acSAndroid Build Coastguard Worker 			tp->queue_depth--;
876*1c60b9acSAndroid Build Coastguard Worker 			tp->done_queue_depth++;
877*1c60b9acSAndroid Build Coastguard Worker 			task->done = lws_now_usecs();
878*1c60b9acSAndroid Build Coastguard Worker 
879*1c60b9acSAndroid Build Coastguard Worker 			lwsl_debug("%s: tp %p: removed queued task %s\n",
880*1c60b9acSAndroid Build Coastguard Worker 				    __func__, tp, lws_wsi_tag(task_to_wsi(task)));
881*1c60b9acSAndroid Build Coastguard Worker 
882*1c60b9acSAndroid Build Coastguard Worker 			break;
883*1c60b9acSAndroid Build Coastguard Worker 		}
884*1c60b9acSAndroid Build Coastguard Worker 		c = &(*c)->task_queue_next;
885*1c60b9acSAndroid Build Coastguard Worker 	}
886*1c60b9acSAndroid Build Coastguard Worker 
887*1c60b9acSAndroid Build Coastguard Worker 	/* is he on the done queue? */
888*1c60b9acSAndroid Build Coastguard Worker 
889*1c60b9acSAndroid Build Coastguard Worker 	c = &tp->task_done_head;
890*1c60b9acSAndroid Build Coastguard Worker 	while (*c) {
891*1c60b9acSAndroid Build Coastguard Worker 		if ((*c) == task) {
892*1c60b9acSAndroid Build Coastguard Worker 			*c = task->task_queue_next;
893*1c60b9acSAndroid Build Coastguard Worker 			task->task_queue_next = NULL;
894*1c60b9acSAndroid Build Coastguard Worker 			lws_threadpool_task_cleanup_destroy(task);
895*1c60b9acSAndroid Build Coastguard Worker 			tp->done_queue_depth--;
896*1c60b9acSAndroid Build Coastguard Worker 			goto bail;
897*1c60b9acSAndroid Build Coastguard Worker 		}
898*1c60b9acSAndroid Build Coastguard Worker 		c = &(*c)->task_queue_next;
899*1c60b9acSAndroid Build Coastguard Worker 	}
900*1c60b9acSAndroid Build Coastguard Worker 
901*1c60b9acSAndroid Build Coastguard Worker 	/* he's not in the queue... is he already running on a thread? */
902*1c60b9acSAndroid Build Coastguard Worker 
903*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < tp->threads_in_pool; n++) {
904*1c60b9acSAndroid Build Coastguard Worker 		if (!tp->pool_list[n].task || tp->pool_list[n].task != task)
905*1c60b9acSAndroid Build Coastguard Worker 			continue;
906*1c60b9acSAndroid Build Coastguard Worker 
907*1c60b9acSAndroid Build Coastguard Worker 		/*
908*1c60b9acSAndroid Build Coastguard Worker 		 * ensure we don't collide with tests or changes in the
909*1c60b9acSAndroid Build Coastguard Worker 		 * worker thread
910*1c60b9acSAndroid Build Coastguard Worker 		 */
911*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&tp->pool_list[n].lock);
912*1c60b9acSAndroid Build Coastguard Worker 
913*1c60b9acSAndroid Build Coastguard Worker 		/*
914*1c60b9acSAndroid Build Coastguard Worker 		 * mark him as having been requested to stop...
915*1c60b9acSAndroid Build Coastguard Worker 		 * the caller will hear about it in his service thread
916*1c60b9acSAndroid Build Coastguard Worker 		 * context as a request to close
917*1c60b9acSAndroid Build Coastguard Worker 		 */
918*1c60b9acSAndroid Build Coastguard Worker 		state_transition(task, LWS_TP_STATUS_STOPPING);
919*1c60b9acSAndroid Build Coastguard Worker 
920*1c60b9acSAndroid Build Coastguard Worker 		/* disconnect from wsi, and wsi from task */
921*1c60b9acSAndroid Build Coastguard Worker 
922*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&task->list);
923*1c60b9acSAndroid Build Coastguard Worker 		task->args.wsi = NULL;
924*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
925*1c60b9acSAndroid Build Coastguard Worker 		task->args.ss = NULL;
926*1c60b9acSAndroid Build Coastguard Worker #endif
927*1c60b9acSAndroid Build Coastguard Worker 
928*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&tp->pool_list[n].lock);
929*1c60b9acSAndroid Build Coastguard Worker 
930*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("%s: tp %p: request stop running task "
931*1c60b9acSAndroid Build Coastguard Worker 			    "for %s\n", __func__, tp,
932*1c60b9acSAndroid Build Coastguard Worker 			    lws_wsi_tag(task_to_wsi(task)));
933*1c60b9acSAndroid Build Coastguard Worker 
934*1c60b9acSAndroid Build Coastguard Worker 		break;
935*1c60b9acSAndroid Build Coastguard Worker 	}
936*1c60b9acSAndroid Build Coastguard Worker 
937*1c60b9acSAndroid Build Coastguard Worker 	if (n == tp->threads_in_pool) {
938*1c60b9acSAndroid Build Coastguard Worker 		/* can't find it */
939*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: tp %p: no task for %s, decoupling\n",
940*1c60b9acSAndroid Build Coastguard Worker 			    __func__, tp, lws_wsi_tag(task_to_wsi(task)));
941*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&task->list);
942*1c60b9acSAndroid Build Coastguard Worker 		task->args.wsi = NULL;
943*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
944*1c60b9acSAndroid Build Coastguard Worker 		task->args.ss = NULL;
945*1c60b9acSAndroid Build Coastguard Worker #endif
946*1c60b9acSAndroid Build Coastguard Worker 	}
947*1c60b9acSAndroid Build Coastguard Worker 
948*1c60b9acSAndroid Build Coastguard Worker bail:
949*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
950*1c60b9acSAndroid Build Coastguard Worker 
951*1c60b9acSAndroid Build Coastguard Worker 	return 0;
952*1c60b9acSAndroid Build Coastguard Worker }
953*1c60b9acSAndroid Build Coastguard Worker 
954*1c60b9acSAndroid Build Coastguard Worker int
lws_threadpool_dequeue(struct lws * wsi)955*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_dequeue(struct lws *wsi) /* deprecated */
956*1c60b9acSAndroid Build Coastguard Worker {
957*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task *task;
958*1c60b9acSAndroid Build Coastguard Worker 
959*1c60b9acSAndroid Build Coastguard Worker 	if (!wsi->tp_task_owner.count)
960*1c60b9acSAndroid Build Coastguard Worker 		return 0;
961*1c60b9acSAndroid Build Coastguard Worker 	assert(wsi->tp_task_owner.count != 1);
962*1c60b9acSAndroid Build Coastguard Worker 
963*1c60b9acSAndroid Build Coastguard Worker 	task = lws_container_of(wsi->tp_task_owner.head,
964*1c60b9acSAndroid Build Coastguard Worker 				struct lws_threadpool_task, list);
965*1c60b9acSAndroid Build Coastguard Worker 
966*1c60b9acSAndroid Build Coastguard Worker 	return lws_threadpool_dequeue_task(task);
967*1c60b9acSAndroid Build Coastguard Worker }
968*1c60b9acSAndroid Build Coastguard Worker 
969*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool_task *
lws_threadpool_enqueue(struct lws_threadpool * tp,const struct lws_threadpool_task_args * args,const char * format,...)970*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_enqueue(struct lws_threadpool *tp,
971*1c60b9acSAndroid Build Coastguard Worker 		       const struct lws_threadpool_task_args *args,
972*1c60b9acSAndroid Build Coastguard Worker 		       const char *format, ...)
973*1c60b9acSAndroid Build Coastguard Worker {
974*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task *task = NULL;
975*1c60b9acSAndroid Build Coastguard Worker 	va_list ap;
976*1c60b9acSAndroid Build Coastguard Worker 
977*1c60b9acSAndroid Build Coastguard Worker 	if (tp->destroying)
978*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
979*1c60b9acSAndroid Build Coastguard Worker 
980*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
981*1c60b9acSAndroid Build Coastguard Worker 	assert(args->ss || args->wsi);
982*1c60b9acSAndroid Build Coastguard Worker #endif
983*1c60b9acSAndroid Build Coastguard Worker 
984*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
985*1c60b9acSAndroid Build Coastguard Worker 
986*1c60b9acSAndroid Build Coastguard Worker 	/*
987*1c60b9acSAndroid Build Coastguard Worker 	 * if there's room on the queue, the job always goes on the queue
988*1c60b9acSAndroid Build Coastguard Worker 	 * first, then any free thread may pick it up after the wake_idle
989*1c60b9acSAndroid Build Coastguard Worker 	 */
990*1c60b9acSAndroid Build Coastguard Worker 
991*1c60b9acSAndroid Build Coastguard Worker 	if (tp->queue_depth == tp->max_queue_depth) {
992*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: queue reached limit %d\n", __func__,
993*1c60b9acSAndroid Build Coastguard Worker 			    tp->max_queue_depth);
994*1c60b9acSAndroid Build Coastguard Worker 
995*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
996*1c60b9acSAndroid Build Coastguard Worker 	}
997*1c60b9acSAndroid Build Coastguard Worker 
998*1c60b9acSAndroid Build Coastguard Worker 	/*
999*1c60b9acSAndroid Build Coastguard Worker 	 * create the task object
1000*1c60b9acSAndroid Build Coastguard Worker 	 */
1001*1c60b9acSAndroid Build Coastguard Worker 
1002*1c60b9acSAndroid Build Coastguard Worker 	task = lws_malloc(sizeof(*task), __func__);
1003*1c60b9acSAndroid Build Coastguard Worker 	if (!task)
1004*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
1005*1c60b9acSAndroid Build Coastguard Worker 
1006*1c60b9acSAndroid Build Coastguard Worker 	memset(task, 0, sizeof(*task));
1007*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_init(&task->wake_idle, NULL);
1008*1c60b9acSAndroid Build Coastguard Worker 	task->args = *args;
1009*1c60b9acSAndroid Build Coastguard Worker 	task->tp = tp;
1010*1c60b9acSAndroid Build Coastguard Worker 	task->created = lws_now_usecs();
1011*1c60b9acSAndroid Build Coastguard Worker 
1012*1c60b9acSAndroid Build Coastguard Worker 	va_start(ap, format);
1013*1c60b9acSAndroid Build Coastguard Worker 	vsnprintf(task->name, sizeof(task->name) - 1, format, ap);
1014*1c60b9acSAndroid Build Coastguard Worker 	va_end(ap);
1015*1c60b9acSAndroid Build Coastguard Worker 
1016*1c60b9acSAndroid Build Coastguard Worker 	/*
1017*1c60b9acSAndroid Build Coastguard Worker 	 * add him on the tp task queue
1018*1c60b9acSAndroid Build Coastguard Worker 	 */
1019*1c60b9acSAndroid Build Coastguard Worker 
1020*1c60b9acSAndroid Build Coastguard Worker 	task->task_queue_next = tp->task_queue_head;
1021*1c60b9acSAndroid Build Coastguard Worker 	state_transition(task, LWS_TP_STATUS_QUEUED);
1022*1c60b9acSAndroid Build Coastguard Worker 	tp->task_queue_head = task;
1023*1c60b9acSAndroid Build Coastguard Worker 	tp->queue_depth++;
1024*1c60b9acSAndroid Build Coastguard Worker 
1025*1c60b9acSAndroid Build Coastguard Worker 	/*
1026*1c60b9acSAndroid Build Coastguard Worker 	 * mark the wsi itself as depending on this tp (so wsi close for
1027*1c60b9acSAndroid Build Coastguard Worker 	 * whatever reason can clean up)
1028*1c60b9acSAndroid Build Coastguard Worker 	 */
1029*1c60b9acSAndroid Build Coastguard Worker 
1030*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
1031*1c60b9acSAndroid Build Coastguard Worker 	if (args->ss)
1032*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_add_tail(&task->list, &args->ss->wsi->tp_task_owner);
1033*1c60b9acSAndroid Build Coastguard Worker 	else
1034*1c60b9acSAndroid Build Coastguard Worker #endif
1035*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_add_tail(&task->list, &args->wsi->tp_task_owner);
1036*1c60b9acSAndroid Build Coastguard Worker 
1037*1c60b9acSAndroid Build Coastguard Worker 	lwsl_thread("%s: tp %s: enqueued task %p (%s) for %s, depth %d\n",
1038*1c60b9acSAndroid Build Coastguard Worker 		    __func__, tp->name, task, task->name,
1039*1c60b9acSAndroid Build Coastguard Worker 		    lws_wsi_tag(task_to_wsi(task)), tp->queue_depth);
1040*1c60b9acSAndroid Build Coastguard Worker 
1041*1c60b9acSAndroid Build Coastguard Worker 	/* alert any idle thread there's something new on the task list */
1042*1c60b9acSAndroid Build Coastguard Worker 
1043*1c60b9acSAndroid Build Coastguard Worker 	lws_memory_barrier();
1044*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_signal(&tp->wake_idle);
1045*1c60b9acSAndroid Build Coastguard Worker 
1046*1c60b9acSAndroid Build Coastguard Worker bail:
1047*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
1048*1c60b9acSAndroid Build Coastguard Worker 
1049*1c60b9acSAndroid Build Coastguard Worker 	return task;
1050*1c60b9acSAndroid Build Coastguard Worker }
1051*1c60b9acSAndroid Build Coastguard Worker 
1052*1c60b9acSAndroid Build Coastguard Worker /* this should be called from the service thread */
1053*1c60b9acSAndroid Build Coastguard Worker 
1054*1c60b9acSAndroid Build Coastguard Worker enum lws_threadpool_task_status
lws_threadpool_task_status(struct lws_threadpool_task * task,void ** user)1055*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_task_status(struct lws_threadpool_task *task, void **user)
1056*1c60b9acSAndroid Build Coastguard Worker {
1057*1c60b9acSAndroid Build Coastguard Worker 	enum lws_threadpool_task_status status;
1058*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool *tp = task->tp;
1059*1c60b9acSAndroid Build Coastguard Worker 
1060*1c60b9acSAndroid Build Coastguard Worker 	if (!tp)
1061*1c60b9acSAndroid Build Coastguard Worker 		return LWS_TP_STATUS_FINISHED;
1062*1c60b9acSAndroid Build Coastguard Worker 
1063*1c60b9acSAndroid Build Coastguard Worker 	*user = task->args.user;
1064*1c60b9acSAndroid Build Coastguard Worker 	status = task->status;
1065*1c60b9acSAndroid Build Coastguard Worker 
1066*1c60b9acSAndroid Build Coastguard Worker 	if (status == LWS_TP_STATUS_FINISHED ||
1067*1c60b9acSAndroid Build Coastguard Worker 	    status == LWS_TP_STATUS_STOPPED) {
1068*1c60b9acSAndroid Build Coastguard Worker 		char buf[160];
1069*1c60b9acSAndroid Build Coastguard Worker 
1070*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&tp->lock); /* ================ tpool lock */
1071*1c60b9acSAndroid Build Coastguard Worker 		__lws_threadpool_task_dump(task, buf, sizeof(buf));
1072*1c60b9acSAndroid Build Coastguard Worker 		lwsl_thread("%s: %s: service thread REAPING: %s\n",
1073*1c60b9acSAndroid Build Coastguard Worker 			    __func__, tp->name, buf);
1074*1c60b9acSAndroid Build Coastguard Worker 		__lws_threadpool_reap(task);
1075*1c60b9acSAndroid Build Coastguard Worker 		lws_memory_barrier();
1076*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&tp->lock); /* ------------ tpool unlock */
1077*1c60b9acSAndroid Build Coastguard Worker 	}
1078*1c60b9acSAndroid Build Coastguard Worker 
1079*1c60b9acSAndroid Build Coastguard Worker 	return status;
1080*1c60b9acSAndroid Build Coastguard Worker }
1081*1c60b9acSAndroid Build Coastguard Worker 
1082*1c60b9acSAndroid Build Coastguard Worker enum lws_threadpool_task_status
lws_threadpool_task_status_noreap(struct lws_threadpool_task * task)1083*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_task_status_noreap(struct lws_threadpool_task *task)
1084*1c60b9acSAndroid Build Coastguard Worker {
1085*1c60b9acSAndroid Build Coastguard Worker 	return task->status;
1086*1c60b9acSAndroid Build Coastguard Worker }
1087*1c60b9acSAndroid Build Coastguard Worker 
1088*1c60b9acSAndroid Build Coastguard Worker enum lws_threadpool_task_status
lws_threadpool_task_status_wsi(struct lws * wsi,struct lws_threadpool_task ** _task,void ** user)1089*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_task_status_wsi(struct lws *wsi,
1090*1c60b9acSAndroid Build Coastguard Worker 			       struct lws_threadpool_task **_task, void **user)
1091*1c60b9acSAndroid Build Coastguard Worker {
1092*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task *task;
1093*1c60b9acSAndroid Build Coastguard Worker 
1094*1c60b9acSAndroid Build Coastguard Worker 	if (!wsi->tp_task_owner.count) {
1095*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: wsi has no task, ~=FINISHED\n", __func__);
1096*1c60b9acSAndroid Build Coastguard Worker 		return LWS_TP_STATUS_FINISHED;
1097*1c60b9acSAndroid Build Coastguard Worker 	}
1098*1c60b9acSAndroid Build Coastguard Worker 
1099*1c60b9acSAndroid Build Coastguard Worker 	assert(wsi->tp_task_owner.count == 1); /* see deprecation docs in hdr */
1100*1c60b9acSAndroid Build Coastguard Worker 
1101*1c60b9acSAndroid Build Coastguard Worker 	task = lws_container_of(wsi->tp_task_owner.head,
1102*1c60b9acSAndroid Build Coastguard Worker 				struct lws_threadpool_task, list);
1103*1c60b9acSAndroid Build Coastguard Worker 
1104*1c60b9acSAndroid Build Coastguard Worker 	*_task = task;
1105*1c60b9acSAndroid Build Coastguard Worker 
1106*1c60b9acSAndroid Build Coastguard Worker 	return lws_threadpool_task_status(task, user);
1107*1c60b9acSAndroid Build Coastguard Worker }
1108*1c60b9acSAndroid Build Coastguard Worker 
1109*1c60b9acSAndroid Build Coastguard Worker void
lws_threadpool_task_sync(struct lws_threadpool_task * task,int stop)1110*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_task_sync(struct lws_threadpool_task *task, int stop)
1111*1c60b9acSAndroid Build Coastguard Worker {
1112*1c60b9acSAndroid Build Coastguard Worker 	lwsl_debug("%s\n", __func__);
1113*1c60b9acSAndroid Build Coastguard Worker 	if (!task)
1114*1c60b9acSAndroid Build Coastguard Worker 		return;
1115*1c60b9acSAndroid Build Coastguard Worker 
1116*1c60b9acSAndroid Build Coastguard Worker 	if (stop)
1117*1c60b9acSAndroid Build Coastguard Worker 		state_transition(task, LWS_TP_STATUS_STOPPING);
1118*1c60b9acSAndroid Build Coastguard Worker 
1119*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&task->tp->lock);
1120*1c60b9acSAndroid Build Coastguard Worker 	pthread_cond_signal(&task->wake_idle);
1121*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&task->tp->lock);
1122*1c60b9acSAndroid Build Coastguard Worker }
1123*1c60b9acSAndroid Build Coastguard Worker 
1124*1c60b9acSAndroid Build Coastguard Worker int
lws_threadpool_foreach_task_wsi(struct lws * wsi,void * user,int (* cb)(struct lws_threadpool_task * task,void * user))1125*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_foreach_task_wsi(struct lws *wsi, void *user,
1126*1c60b9acSAndroid Build Coastguard Worker 				int (*cb)(struct lws_threadpool_task *task,
1127*1c60b9acSAndroid Build Coastguard Worker 					  void *user))
1128*1c60b9acSAndroid Build Coastguard Worker {
1129*1c60b9acSAndroid Build Coastguard Worker 	struct lws_threadpool_task *task1;
1130*1c60b9acSAndroid Build Coastguard Worker 
1131*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->tp_task_owner.head == NULL)
1132*1c60b9acSAndroid Build Coastguard Worker 		return 0;
1133*1c60b9acSAndroid Build Coastguard Worker 
1134*1c60b9acSAndroid Build Coastguard Worker 	task1 = lws_container_of(wsi->tp_task_owner.head,
1135*1c60b9acSAndroid Build Coastguard Worker 				 struct lws_threadpool_task, list);
1136*1c60b9acSAndroid Build Coastguard Worker 
1137*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_lock(&task1->tp->lock); /* ================ tpool lock */
1138*1c60b9acSAndroid Build Coastguard Worker 
1139*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1140*1c60b9acSAndroid Build Coastguard Worker 				   wsi->tp_task_owner.head) {
1141*1c60b9acSAndroid Build Coastguard Worker 		struct lws_threadpool_task *task = lws_container_of(d,
1142*1c60b9acSAndroid Build Coastguard Worker 					struct lws_threadpool_task, list);
1143*1c60b9acSAndroid Build Coastguard Worker 
1144*1c60b9acSAndroid Build Coastguard Worker 		if (cb(task, user)) {
1145*1c60b9acSAndroid Build Coastguard Worker 			pthread_mutex_unlock(&task1->tp->lock); /* ------------ tpool unlock */
1146*1c60b9acSAndroid Build Coastguard Worker 			return 1;
1147*1c60b9acSAndroid Build Coastguard Worker 		}
1148*1c60b9acSAndroid Build Coastguard Worker 
1149*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
1150*1c60b9acSAndroid Build Coastguard Worker 
1151*1c60b9acSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&task1->tp->lock); /* ------------ tpool unlock */
1152*1c60b9acSAndroid Build Coastguard Worker 
1153*1c60b9acSAndroid Build Coastguard Worker 	return 0;
1154*1c60b9acSAndroid Build Coastguard Worker }
1155*1c60b9acSAndroid Build Coastguard Worker 
1156*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
1157*1c60b9acSAndroid Build Coastguard Worker int
lws_threadpool_foreach_task_ss(struct lws_ss_handle * ss,void * user,int (* cb)(struct lws_threadpool_task * task,void * user))1158*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_foreach_task_ss(struct lws_ss_handle *ss, void *user,
1159*1c60b9acSAndroid Build Coastguard Worker 			       int (*cb)(struct lws_threadpool_task *task,
1160*1c60b9acSAndroid Build Coastguard Worker 					 void *user))
1161*1c60b9acSAndroid Build Coastguard Worker {
1162*1c60b9acSAndroid Build Coastguard Worker 	if (!ss->wsi)
1163*1c60b9acSAndroid Build Coastguard Worker 		return 0;
1164*1c60b9acSAndroid Build Coastguard Worker 
1165*1c60b9acSAndroid Build Coastguard Worker 	return lws_threadpool_foreach_task_wsi(ss->wsi, user, cb);
1166*1c60b9acSAndroid Build Coastguard Worker }
1167*1c60b9acSAndroid Build Coastguard Worker #endif
1168*1c60b9acSAndroid Build Coastguard Worker 
1169*1c60b9acSAndroid Build Coastguard Worker static int
disassociate_wsi(struct lws_threadpool_task * task,void * user)1170*1c60b9acSAndroid Build Coastguard Worker disassociate_wsi(struct lws_threadpool_task *task,
1171*1c60b9acSAndroid Build Coastguard Worker 		  void *user)
1172*1c60b9acSAndroid Build Coastguard Worker {
1173*1c60b9acSAndroid Build Coastguard Worker 	task->args.wsi = NULL;
1174*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&task->list);
1175*1c60b9acSAndroid Build Coastguard Worker 
1176*1c60b9acSAndroid Build Coastguard Worker 	return 0;
1177*1c60b9acSAndroid Build Coastguard Worker }
1178*1c60b9acSAndroid Build Coastguard Worker 
1179*1c60b9acSAndroid Build Coastguard Worker void
lws_threadpool_wsi_closing(struct lws * wsi)1180*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_wsi_closing(struct lws *wsi)
1181*1c60b9acSAndroid Build Coastguard Worker {
1182*1c60b9acSAndroid Build Coastguard Worker 	lws_threadpool_foreach_task_wsi(wsi, NULL, disassociate_wsi);
1183*1c60b9acSAndroid Build Coastguard Worker }
1184*1c60b9acSAndroid Build Coastguard Worker 
1185*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool_task *
lws_threadpool_get_task_wsi(struct lws * wsi)1186*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_get_task_wsi(struct lws *wsi)
1187*1c60b9acSAndroid Build Coastguard Worker {
1188*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->tp_task_owner.head == NULL)
1189*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
1190*1c60b9acSAndroid Build Coastguard Worker 
1191*1c60b9acSAndroid Build Coastguard Worker 	return lws_container_of(wsi->tp_task_owner.head,
1192*1c60b9acSAndroid Build Coastguard Worker 				 struct lws_threadpool_task, list);
1193*1c60b9acSAndroid Build Coastguard Worker }
1194*1c60b9acSAndroid Build Coastguard Worker 
1195*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
1196*1c60b9acSAndroid Build Coastguard Worker struct lws_threadpool_task *
lws_threadpool_get_task_ss(struct lws_ss_handle * ss)1197*1c60b9acSAndroid Build Coastguard Worker lws_threadpool_get_task_ss(struct lws_ss_handle *ss)
1198*1c60b9acSAndroid Build Coastguard Worker {
1199*1c60b9acSAndroid Build Coastguard Worker 	return lws_threadpool_get_task_wsi(ss->wsi);
1200*1c60b9acSAndroid Build Coastguard Worker }
1201*1c60b9acSAndroid Build Coastguard Worker #endif
1202