1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci#include "private-lib-event-libs-uloop.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#define pt_to_priv_uloop(_pt) ((struct lws_pt_eventlibs_uloop *)(_pt)->evlib_pt)
29d4afb5ceSopenharmony_ci#define wsi_to_priv_uloop(_w) ((struct lws_wsi_eventlibs_uloop *)(_w)->evlib_wsi)
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_cistatic void
32d4afb5ceSopenharmony_cilws_uloop_hrtimer_cb(struct uloop_timeout *ti)
33d4afb5ceSopenharmony_ci{
34d4afb5ceSopenharmony_ci	struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti,
35d4afb5ceSopenharmony_ci					struct lws_pt_eventlibs_uloop, hrtimer);
36d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = upt->pt;
37d4afb5ceSopenharmony_ci	lws_usec_t us;
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
40d4afb5ceSopenharmony_ci	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
41d4afb5ceSopenharmony_ci				    lws_now_usecs());
42d4afb5ceSopenharmony_ci	if (us)
43d4afb5ceSopenharmony_ci		uloop_timeout_set(ti, us < 1000 ? 1 : (int)(us / 1000));
44d4afb5ceSopenharmony_ci
45d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
46d4afb5ceSopenharmony_ci}
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_cistatic void
49d4afb5ceSopenharmony_cilws_uloop_idle_timer_cb(struct uloop_timeout *ti)
50d4afb5ceSopenharmony_ci{
51d4afb5ceSopenharmony_ci	struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti,
52d4afb5ceSopenharmony_ci						struct lws_pt_eventlibs_uloop,
53d4afb5ceSopenharmony_ci						idle_timer);
54d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = upt->pt;
55d4afb5ceSopenharmony_ci	lws_usec_t us;
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci	if (pt->is_destroyed)
58d4afb5ceSopenharmony_ci		return;
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci	lws_service_do_ripe_rxflow(pt);
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci	/*
63d4afb5ceSopenharmony_ci	 * is there anybody with pending stuff that needs service forcing?
64d4afb5ceSopenharmony_ci	 */
65d4afb5ceSopenharmony_ci	if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
66d4afb5ceSopenharmony_ci		/* -1 timeout means just do forced service */
67d4afb5ceSopenharmony_ci		_lws_plat_service_forced_tsi(pt->context, pt->tid);
68d4afb5ceSopenharmony_ci		/* still somebody left who wants forced service? */
69d4afb5ceSopenharmony_ci		if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
70d4afb5ceSopenharmony_ci			/* yes... come back again later */
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci			uloop_timeout_set(ti, 1 /* 1ms */);
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci			return;
75d4afb5ceSopenharmony_ci		}
76d4afb5ceSopenharmony_ci	}
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	/* account for hrtimer */
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci	lws_pt_lock(pt, __func__);
81d4afb5ceSopenharmony_ci	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
82d4afb5ceSopenharmony_ci				    lws_now_usecs());
83d4afb5ceSopenharmony_ci	if (us) {
84d4afb5ceSopenharmony_ci		uloop_timeout_cancel(&upt->hrtimer);
85d4afb5ceSopenharmony_ci		uloop_timeout_set(&upt->hrtimer,
86d4afb5ceSopenharmony_ci				  us < 1000 ? 1 : (int)(us / 1000));
87d4afb5ceSopenharmony_ci	}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	lws_pt_unlock(pt);
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	if (pt->destroy_self)
92d4afb5ceSopenharmony_ci		lws_context_destroy(pt->context);
93d4afb5ceSopenharmony_ci}
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_cistatic void
96d4afb5ceSopenharmony_cilws_uloop_cb(struct uloop_fd *ufd, unsigned int revents)
97d4afb5ceSopenharmony_ci{
98d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu = lws_container_of(ufd,
99d4afb5ceSopenharmony_ci					struct lws_wsi_eventlibs_uloop, fd);
100d4afb5ceSopenharmony_ci	struct lws_context *context = wu->wsi->a.context;
101d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
102d4afb5ceSopenharmony_ci	struct lws_pollfd eventfd;
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	eventfd.fd = wu->wsi->desc.sockfd;
105d4afb5ceSopenharmony_ci	eventfd.events = 0;
106d4afb5ceSopenharmony_ci	eventfd.revents = 0;
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	if (revents & ULOOP_READ) {
109d4afb5ceSopenharmony_ci		eventfd.events = LWS_POLLIN;
110d4afb5ceSopenharmony_ci		eventfd.revents = LWS_POLLIN;
111d4afb5ceSopenharmony_ci	}
112d4afb5ceSopenharmony_ci	if (revents & ULOOP_WRITE) {
113d4afb5ceSopenharmony_ci		eventfd.events |= LWS_POLLOUT;
114d4afb5ceSopenharmony_ci		eventfd.revents |= LWS_POLLOUT;
115d4afb5ceSopenharmony_ci	}
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_ci	pt = &context->pt[(int)wu->wsi->tsi];
118d4afb5ceSopenharmony_ci	if (pt->is_destroyed)
119d4afb5ceSopenharmony_ci		return;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	lws_service_fd_tsi(context, &eventfd, wu->wsi->tsi);
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci	if (pt->destroy_self) {
124d4afb5ceSopenharmony_ci		lwsl_cx_notice(context, "pt destroy self coming true");
125d4afb5ceSopenharmony_ci		lws_context_destroy(pt->context);
126d4afb5ceSopenharmony_ci		return;
127d4afb5ceSopenharmony_ci	}
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	/* set the idle timer for 1ms ahead */
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ci	uloop_timeout_cancel(&pt_to_priv_uloop(pt)->idle_timer);
132d4afb5ceSopenharmony_ci	uloop_timeout_set(&pt_to_priv_uloop(pt)->idle_timer, 1);
133d4afb5ceSopenharmony_ci}
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_cistatic int
136d4afb5ceSopenharmony_cielops_listen_init_uloop(struct lws_dll2 *d, void *user)
137d4afb5ceSopenharmony_ci{
138d4afb5ceSopenharmony_ci	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
139d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	wu->wsi = wsi;
142d4afb5ceSopenharmony_ci	wu->fd.fd = wsi->desc.sockfd;
143d4afb5ceSopenharmony_ci	wu->fd.cb = lws_uloop_cb;
144d4afb5ceSopenharmony_ci	uloop_fd_add(&wu->fd,  ULOOP_READ);
145d4afb5ceSopenharmony_ci	wu->actual_events = ULOOP_READ;
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci	return 0;
148d4afb5ceSopenharmony_ci}
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_cistatic int
151d4afb5ceSopenharmony_cielops_init_pt_uloop(struct lws_context *context, void *v, int tsi)
152d4afb5ceSopenharmony_ci{
153d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[tsi];
154d4afb5ceSopenharmony_ci	struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt);
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	ptpr->pt = pt;
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci	lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_uloop);
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci	/* static event loop objects */
161d4afb5ceSopenharmony_ci
162d4afb5ceSopenharmony_ci	ptpr->hrtimer.cb = lws_uloop_hrtimer_cb;
163d4afb5ceSopenharmony_ci	ptpr->idle_timer.cb = lws_uloop_idle_timer_cb;
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	uloop_timeout_add(&ptpr->hrtimer);
166d4afb5ceSopenharmony_ci	uloop_timeout_add(&ptpr->idle_timer);
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	uloop_timeout_set(&ptpr->hrtimer, 1);
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci	return 0;
171d4afb5ceSopenharmony_ci}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_cistatic int
174d4afb5ceSopenharmony_cielops_accept_uloop(struct lws *wsi)
175d4afb5ceSopenharmony_ci{
176d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci	wu->wsi = wsi;
179d4afb5ceSopenharmony_ci	wu->fd.fd = wsi->desc.sockfd;
180d4afb5ceSopenharmony_ci	wu->fd.cb = lws_uloop_cb;
181d4afb5ceSopenharmony_ci	uloop_fd_add(&wu->fd, ULOOP_READ);
182d4afb5ceSopenharmony_ci	wu->actual_events = ULOOP_READ;
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	return 0;
185d4afb5ceSopenharmony_ci}
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_cistatic void
188d4afb5ceSopenharmony_cielops_io_uloop(struct lws *wsi, unsigned int flags)
189d4afb5ceSopenharmony_ci{
190d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
191d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
192d4afb5ceSopenharmony_ci	unsigned int ulf = (unsigned int)(((flags & LWS_EV_WRITE) ? ULOOP_WRITE : 0) |
193d4afb5ceSopenharmony_ci			    ((flags & LWS_EV_READ) ? ULOOP_READ : 0)), u;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	if (wsi->a.context->being_destroyed || pt->is_destroyed)
196d4afb5ceSopenharmony_ci		return;
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci	assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
199d4afb5ceSopenharmony_ci	       (flags & (LWS_EV_READ | LWS_EV_WRITE)));
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	u = wu->actual_events;
202d4afb5ceSopenharmony_ci	if (flags & LWS_EV_START)
203d4afb5ceSopenharmony_ci		u |= ulf;
204d4afb5ceSopenharmony_ci	if (flags & LWS_EV_STOP)
205d4afb5ceSopenharmony_ci		u &= ~ulf;
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci	uloop_fd_add(&wu->fd, u);
208d4afb5ceSopenharmony_ci	wu->actual_events = u;
209d4afb5ceSopenharmony_ci}
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_cistatic void
212d4afb5ceSopenharmony_cielops_run_pt_uloop(struct lws_context *context, int tsi)
213d4afb5ceSopenharmony_ci{
214d4afb5ceSopenharmony_ci	uloop_run();
215d4afb5ceSopenharmony_ci}
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_cistatic int
218d4afb5ceSopenharmony_cielops_listen_destroy_uloop(struct lws_dll2 *d, void *user)
219d4afb5ceSopenharmony_ci{
220d4afb5ceSopenharmony_ci	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
221d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	uloop_fd_delete(&wu->fd);
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	return 0;
226d4afb5ceSopenharmony_ci}
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_cistatic void
229d4afb5ceSopenharmony_cielops_destroy_pt_uloop(struct lws_context *context, int tsi)
230d4afb5ceSopenharmony_ci{
231d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[tsi];
232d4afb5ceSopenharmony_ci	struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt);
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_uloop);
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	uloop_timeout_cancel(&ptpr->hrtimer);
237d4afb5ceSopenharmony_ci	uloop_timeout_cancel(&ptpr->idle_timer);
238d4afb5ceSopenharmony_ci}
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_cistatic void
241d4afb5ceSopenharmony_cielops_destroy_wsi_uloop(struct lws *wsi)
242d4afb5ceSopenharmony_ci{
243d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt;
244d4afb5ceSopenharmony_ci
245d4afb5ceSopenharmony_ci	if (!wsi)
246d4afb5ceSopenharmony_ci		return;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	pt = &wsi->a.context->pt[(int)wsi->tsi];
249d4afb5ceSopenharmony_ci	if (pt->is_destroyed)
250d4afb5ceSopenharmony_ci		return;
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	uloop_fd_delete(&wsi_to_priv_uloop(wsi)->fd);
253d4afb5ceSopenharmony_ci}
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_cistatic int
256d4afb5ceSopenharmony_cielops_wsi_logical_close_uloop(struct lws *wsi)
257d4afb5ceSopenharmony_ci{
258d4afb5ceSopenharmony_ci	elops_destroy_wsi_uloop(wsi);
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci	return 0;
261d4afb5ceSopenharmony_ci}
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_cistatic int
264d4afb5ceSopenharmony_cielops_init_vhost_listen_wsi_uloop(struct lws *wsi)
265d4afb5ceSopenharmony_ci{
266d4afb5ceSopenharmony_ci	struct lws_wsi_eventlibs_uloop *wu;
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci	if (!wsi) {
269d4afb5ceSopenharmony_ci		assert(0);
270d4afb5ceSopenharmony_ci		return 0;
271d4afb5ceSopenharmony_ci	}
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci	wu = wsi_to_priv_uloop(wsi);
274d4afb5ceSopenharmony_ci	wu->wsi = wsi;
275d4afb5ceSopenharmony_ci	wu->fd.fd = wsi->desc.sockfd;
276d4afb5ceSopenharmony_ci	wu->fd.cb = lws_uloop_cb;
277d4afb5ceSopenharmony_ci	uloop_fd_add(&wu->fd,  ULOOP_READ);
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci	wu->actual_events = ULOOP_READ;
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci	return 0;
282d4afb5ceSopenharmony_ci}
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_cistatic const struct lws_event_loop_ops event_loop_ops_uloop = {
285d4afb5ceSopenharmony_ci	/* name */			"uloop",
286d4afb5ceSopenharmony_ci	/* init_context */		NULL,
287d4afb5ceSopenharmony_ci	/* destroy_context1 */		NULL,
288d4afb5ceSopenharmony_ci	/* destroy_context2 */		NULL,
289d4afb5ceSopenharmony_ci	/* init_vhost_listen_wsi */	elops_init_vhost_listen_wsi_uloop,
290d4afb5ceSopenharmony_ci	/* init_pt */			elops_init_pt_uloop,
291d4afb5ceSopenharmony_ci	/* wsi_logical_close */		elops_wsi_logical_close_uloop,
292d4afb5ceSopenharmony_ci	/* check_client_connect_ok */	NULL,
293d4afb5ceSopenharmony_ci	/* close_handle_manually */	NULL,
294d4afb5ceSopenharmony_ci	/* accept */			elops_accept_uloop,
295d4afb5ceSopenharmony_ci	/* io */			elops_io_uloop,
296d4afb5ceSopenharmony_ci	/* run_pt */			elops_run_pt_uloop,
297d4afb5ceSopenharmony_ci	/* destroy_pt */		elops_destroy_pt_uloop,
298d4afb5ceSopenharmony_ci	/* destroy wsi */		elops_destroy_wsi_uloop,
299d4afb5ceSopenharmony_ci	/* foreign_thread */		NULL,
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci	/* flags */			0,
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci	/* evlib_size_ctx */	0,
304d4afb5ceSopenharmony_ci	/* evlib_size_pt */	sizeof(struct lws_pt_eventlibs_uloop),
305d4afb5ceSopenharmony_ci	/* evlib_size_vh */	0,
306d4afb5ceSopenharmony_ci	/* evlib_size_wsi */	sizeof(struct lws_wsi_eventlibs_uloop),
307d4afb5ceSopenharmony_ci};
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_ci#if defined(LWS_WITH_EVLIB_PLUGINS)
310d4afb5ceSopenharmony_ciLWS_VISIBLE
311d4afb5ceSopenharmony_ci#endif
312d4afb5ceSopenharmony_ciconst lws_plugin_evlib_t evlib_uloop = {
313d4afb5ceSopenharmony_ci	.hdr = {
314d4afb5ceSopenharmony_ci		"uloop event loop",
315d4afb5ceSopenharmony_ci		"lws_evlib_plugin",
316d4afb5ceSopenharmony_ci		LWS_BUILD_HASH,
317d4afb5ceSopenharmony_ci		LWS_PLUGIN_API_MAGIC
318d4afb5ceSopenharmony_ci	},
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	.ops	= &event_loop_ops_uloop
321d4afb5ceSopenharmony_ci};
322