xref: /aosp_15_r20/external/libwebsockets/lib/plat/freertos/freertos-service.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 int
lws_plat_service(struct lws_context * context,int timeout_ms)28 lws_plat_service(struct lws_context *context, int timeout_ms)
29 {
30 	int n = _lws_plat_service_tsi(context, timeout_ms, 0);
31 
32 #if !defined(LWS_AMAZON_RTOS)
33 	esp_task_wdt_reset();
34 #endif
35 
36 	return n;
37 }
38 
39 
40 int
_lws_plat_service_tsi(struct lws_context * context,int timeout_ms,int tsi)41 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
42 {
43 	volatile struct lws_context_per_thread *vpt;
44 	struct lws_context_per_thread *pt;
45 	lws_usec_t timeout_us;
46 	int n = -1, m, c, a = 0;
47 
48 	/* stay dead once we are dead */
49 
50 	if (!context)
51 		return 1;
52 
53 	pt = &context->pt[tsi];
54 	vpt = (volatile struct lws_context_per_thread *)pt;
55 
56 	{
57 		unsigned long m = lws_now_secs();
58 
59 		if (m > context->time_last_state_dump) {
60 			context->time_last_state_dump = m;
61 #if defined(LWS_ESP_PLATFORM)
62 			n = esp_get_free_heap_size();
63 #else
64 			n = xPortGetFreeHeapSize();
65 #endif
66 			if ((unsigned int)n != context->last_free_heap) {
67 				if ((unsigned int)n > context->last_free_heap)
68 					lwsl_debug(" heap :%ld (+%ld)\n",
69 						    (unsigned long)n,
70 						    (unsigned long)(n -
71 						      context->last_free_heap));
72 				else
73 					lwsl_debug(" heap :%ld (-%ld)\n",
74 						    (unsigned long)n,
75 						    (unsigned long)(
76 						      context->last_free_heap -
77 						      n));
78 				context->last_free_heap = n;
79 			}
80 		}
81 	}
82 
83 	if (timeout_ms < 0)
84 		timeout_ms = 0;
85 	else
86 		/* force a default timeout of 23 days */
87 		timeout_ms = 2000000000;
88 	timeout_us = ((lws_usec_t)timeout_ms) * LWS_US_PER_MS;
89 
90 	if (!pt->service_tid_detected && context->vhost_list) {
91 		lws_fakewsi_def_plwsa(pt);
92 
93 		lws_fakewsi_prep_plwsa_ctx(context);
94 
95 		pt->service_tid = context->vhost_list->protocols[0].callback(
96 			(struct lws *)plwsa, LWS_CALLBACK_GET_THREAD_ID,
97 			NULL, NULL, 0);
98 		pt->service_tid_detected = 1;
99 	}
100 
101 	/*
102 	 * is there anybody with pending stuff that needs service forcing?
103 	 */
104 #if !defined(LWS_AMAZON_RTOS)
105 again:
106 #endif
107 	n = 0;
108 	if (lws_service_adjust_timeout(context, 1, tsi)) {
109 #if defined(LWS_AMAZON_RTOS)
110 again:
111 #endif /* LWS_AMAZON_RTOS */
112 
113 		a = 0;
114 		if (timeout_us) {
115 			lws_usec_t us;
116 
117 			lws_pt_lock(pt, __func__);
118 			/* don't stay in poll wait longer than next hr timeout */
119 			us = __lws_sul_service_ripe(pt->pt_sul_owner,
120 						    LWS_COUNT_PT_SUL_OWNERS,
121 						    lws_now_usecs());
122 			if (us && us < timeout_us)
123 				timeout_us = us;
124 
125 			lws_pt_unlock(pt);
126 		}
127 
128 	//	n = poll(pt->fds, pt->fds_count, timeout_ms);
129 		{
130 			fd_set readfds, writefds, errfds;
131 			struct timeval tv = { timeout_us / LWS_US_PER_SEC,
132 					      timeout_us % LWS_US_PER_SEC }, *ptv = &tv;
133 			int max_fd = 0;
134 			FD_ZERO(&readfds);
135 			FD_ZERO(&writefds);
136 			FD_ZERO(&errfds);
137 
138 			for (n = 0; n < (int)pt->fds_count; n++) {
139 				pt->fds[n].revents = 0;
140 				if (pt->fds[n].fd >= max_fd)
141 					max_fd = pt->fds[n].fd;
142 				if (pt->fds[n].events & LWS_POLLIN)
143 					FD_SET(pt->fds[n].fd, &readfds);
144 				if (pt->fds[n].events & LWS_POLLOUT)
145 					FD_SET(pt->fds[n].fd, &writefds);
146 				FD_SET(pt->fds[n].fd, &errfds);
147 			}
148 
149 			vpt->inside_poll = 1;
150 			lws_memory_barrier();
151 			n = select(max_fd + 1, &readfds, &writefds, &errfds, ptv);
152 			vpt->inside_poll = 0;
153 			lws_memory_barrier();
154 			n = 0;
155 
156 			for (m = 0; m < (int)pt->fds_count; m++) {
157 				c = 0;
158 				if (FD_ISSET(pt->fds[m].fd, &readfds)) {
159 					pt->fds[m].revents |= LWS_POLLIN;
160 					c = 1;
161 				}
162 				if (FD_ISSET(pt->fds[m].fd, &writefds)) {
163 					pt->fds[m].revents |= LWS_POLLOUT;
164 					c = 1;
165 				}
166 				if (FD_ISSET(pt->fds[m].fd, &errfds)) {
167 					// lwsl_notice("errfds %d\n", pt->fds[m].fd);
168 					pt->fds[m].revents |= LWS_POLLHUP;
169 					c = 1;
170 				}
171 
172 				if (c)
173 					n++;
174 			}
175 		}
176 
177 		m = 0;
178 
179 	#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
180 		m |= !!pt->ws.rx_draining_ext_list;
181 	#endif
182 
183 #if defined(LWS_WITH_TLS)
184 		if (pt->context->tls_ops &&
185 		    pt->context->tls_ops->fake_POLLIN_for_buffered)
186 			m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
187 #endif
188 		if (!m && !n)
189 			return 0;
190 	} else
191 		a = 1;
192 
193 	m = lws_service_flag_pending(context, tsi);
194 	c = m ? -1 : n;
195 
196 	/* any socket with events to service? */
197 	for (n = 0; n < (int)pt->fds_count && c; n++) {
198 		if (!pt->fds[n].revents)
199 			continue;
200 
201 		c--;
202 
203 		m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
204 		if (m < 0)
205 			return -1;
206 		/* if something closed, retry this slot */
207 		if (m)
208 			n--;
209 	}
210 
211 	if (a)
212 		goto again;
213 
214 	return 0;
215 }
216