1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
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#include "private-lib-event-libs-libev.h"
27
28#define pt_to_priv_ev(_pt) ((struct lws_pt_eventlibs_libev *)(_pt)->evlib_pt)
29#define vh_to_priv_ev(_vh) ((struct lws_vh_eventlibs_libev *)(_vh)->evlib_vh)
30#define wsi_to_priv_ev(_w) ((struct lws_wsi_eventlibs_libev *)(_w)->evlib_wsi)
31
32static void
33lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
34{
35	struct lws_pt_eventlibs_libev *ptpr = lws_container_of(watcher,
36					struct lws_pt_eventlibs_libev, hrtimer);
37	struct lws_context_per_thread *pt = ptpr->pt;
38	lws_usec_t us;
39
40	lws_pt_lock(pt, __func__);
41	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
42				    lws_now_usecs());
43	if (us) {
44		ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
45		ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
46	}
47	lws_pt_unlock(pt);
48}
49
50static void
51lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents)
52{
53	struct lws_pt_eventlibs_libev *ptpr = lws_container_of(handle,
54					struct lws_pt_eventlibs_libev, idle);
55	struct lws_context_per_thread *pt = ptpr->pt;
56	int reschedule = 0;
57	lws_usec_t us;
58
59	lws_service_do_ripe_rxflow(pt);
60
61	/*
62	 * is there anybody with pending stuff that needs service forcing?
63	 */
64	if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
65		/* -1 timeout means just do forced service */
66		reschedule = _lws_plat_service_forced_tsi(pt->context, pt->tid);
67
68	/* account for hrtimer */
69
70	lws_pt_lock(pt, __func__);
71	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
72				    lws_now_usecs());
73	if (us) {
74		ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
75		ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
76	}
77	lws_pt_unlock(pt);
78
79	/* there is nobody who needs service forcing, shut down idle */
80	if (!reschedule)
81		ev_idle_stop(loop, handle);
82
83	if (pt->destroy_self)
84		lws_context_destroy(pt->context);
85}
86
87static void
88lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
89{
90	struct lws_io_watcher_libev *lws_io = lws_container_of(watcher,
91					struct lws_io_watcher_libev, watcher);
92	struct lws_context *context = lws_io->context;
93	struct lws_pt_eventlibs_libev *ptpr;
94	struct lws_context_per_thread *pt;
95	struct lws_pollfd eventfd;
96	struct lws *wsi;
97
98	if (revents & EV_ERROR)
99		return;
100
101	eventfd.fd = watcher->fd;
102	eventfd.events = 0;
103	eventfd.revents = EV_NONE;
104
105	if (revents & EV_READ) {
106		eventfd.events |= LWS_POLLIN;
107		eventfd.revents |= LWS_POLLIN;
108	}
109	if (revents & EV_WRITE) {
110		eventfd.events |= LWS_POLLOUT;
111		eventfd.revents |= LWS_POLLOUT;
112	}
113
114	wsi = wsi_from_fd(context, watcher->fd);
115	pt = &context->pt[(int)wsi->tsi];
116	ptpr = pt_to_priv_ev(pt);
117
118	lws_service_fd_tsi(context, &eventfd, (int)wsi->tsi);
119
120	ev_idle_start(ptpr->io_loop, &ptpr->idle);
121}
122
123void
124lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
125{
126	struct lws_context *context = watcher->data;
127
128	if (context->eventlib_signal_cb) {
129		context->eventlib_signal_cb((void *)watcher, watcher->signum);
130
131		return;
132	}
133	ev_break(loop, EVBREAK_ALL);
134}
135
136static int
137elops_listen_init_ev(struct lws_dll2 *d, void *user)
138{
139	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
140	struct lws_context *context = (struct lws_context *)user;
141	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
142	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
143	struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
144	struct lws_vhost *vh = wsi->a.vhost;
145
146	w->w_read.context = context;
147	w->w_write.context = context;
148	vh_to_priv_ev(vh)->w_accept.context = context;
149
150	ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher,
151		   lws_accept_cb, wsi->desc.sockfd, EV_READ);
152	ev_io_start(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
153
154	return 0;
155}
156
157static int
158elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
159{
160	struct lws_context_per_thread *pt = &context->pt[tsi];
161	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
162	struct ev_signal *w_sigint = &ptpr->w_sigint.watcher;
163	struct ev_loop *loop = (struct ev_loop *)_loop;
164	const char *backend_name;
165	unsigned int backend;
166	int status = 0;
167
168	lwsl_cx_info(context, "loop %p", _loop);
169
170	ptpr->pt = pt;
171
172	if (!loop)
173		loop = ev_loop_new(0);
174	else
175		context->pt[tsi].event_loop_foreign = 1;
176
177	if (!loop) {
178		lwsl_cx_err(context, "creating event base failed");
179
180		return -1;
181	}
182
183	ptpr->io_loop = loop;
184
185	lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_ev);
186
187	/* Register the signal watcher unless it's a foreign loop */
188	if (!context->pt[tsi].event_loop_foreign) {
189		ev_signal_init(w_sigint, lws_ev_sigint_cb, SIGINT);
190		w_sigint->data = context;
191		ev_signal_start(loop, w_sigint);
192	}
193
194	backend = ev_backend(loop);
195	switch (backend) {
196	case EVBACKEND_SELECT:
197		backend_name = "select";
198		break;
199	case EVBACKEND_POLL:
200		backend_name = "poll";
201		break;
202	case EVBACKEND_EPOLL:
203		backend_name = "epoll";
204		break;
205#if defined(LWS_HAVE_EVBACKEND_LINUXAIO)
206       case EVBACKEND_LINUXAIO:
207               backend_name = "Linux AIO";
208               break;
209#endif
210#if defined(LWS_HAVE_EVBACKEND_IOURING)
211       case EVBACKEND_IOURING:
212               backend_name = "Linux io_uring";
213               break;
214#endif
215       case EVBACKEND_KQUEUE:
216		backend_name = "kqueue";
217		break;
218	case EVBACKEND_DEVPOLL:
219		backend_name = "/dev/poll";
220		break;
221	case EVBACKEND_PORT:
222		backend_name = "Solaris 10 \"port\"";
223		break;
224	default:
225		backend_name = "Unknown libev backend";
226		break;
227	}
228
229	lwsl_cx_info(context, " libev backend: %s", backend_name);
230	(void)backend_name;
231
232	ev_timer_init(&ptpr->hrtimer, lws_ev_hrtimer_cb, 0, 0);
233	ptpr->hrtimer.data = pt;
234
235	ev_idle_init(&ptpr->idle, lws_ev_idle_cb);
236
237	return status;
238}
239
240static int
241elops_listen_destroy_ev(struct lws_dll2 *d, void *user)
242{
243	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
244	struct lws_context *context = (struct lws_context *)user;
245	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
246	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
247	struct lws_vhost *vh = wsi->a.vhost;
248
249	ev_io_stop(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
250
251	return 0;
252}
253
254static void
255elops_destroy_pt_ev(struct lws_context *context, int tsi)
256{
257	struct lws_context_per_thread *pt = &context->pt[tsi];
258	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
259
260	lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_ev);
261
262	/* static assets */
263
264	ev_timer_stop(ptpr->io_loop, &ptpr->hrtimer);
265	ev_idle_stop(ptpr->io_loop, &ptpr->idle);
266
267	if (!pt->event_loop_foreign)
268		ev_signal_stop(ptpr->io_loop, &ptpr->w_sigint.watcher);
269}
270
271static int
272elops_init_context_ev(struct lws_context *context,
273		      const struct lws_context_creation_info *info)
274{
275	int n;
276
277	context->eventlib_signal_cb = info->signal_cb;
278
279	for (n = 0; n < context->count_threads; n++)
280		pt_to_priv_ev(&context->pt[n])->w_sigint.context = context;
281
282	return 0;
283}
284
285static int
286elops_accept_ev(struct lws *wsi)
287{
288	struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
289	int fd;
290
291	if (wsi->role_ops->file_handle)
292		fd = wsi->desc.filefd;
293	else
294		fd = wsi->desc.sockfd;
295
296	w->w_read.context = wsi->a.context;
297	w->w_write.context = wsi->a.context;
298
299	ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
300	ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
301
302	return 0;
303}
304
305static void
306elops_io_ev(struct lws *wsi, unsigned int flags)
307{
308	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
309	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
310	struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
311
312	lwsl_wsi_debug(wsi, "%s flags 0x%x %p %d", wsi->role_ops->name, flags,
313						   ptpr->io_loop,
314						   pt->is_destroyed);
315
316	if (!ptpr->io_loop || pt->is_destroyed)
317		return;
318
319	assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
320	       (flags & (LWS_EV_READ | LWS_EV_WRITE)));
321
322	if (flags & LWS_EV_START) {
323		if (flags & LWS_EV_WRITE)
324			ev_io_start(ptpr->io_loop, &w->w_write.watcher);
325		if (flags & LWS_EV_READ)
326			ev_io_start(ptpr->io_loop, &w->w_read.watcher);
327	} else {
328		if (flags & LWS_EV_WRITE)
329			ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
330		if (flags & LWS_EV_READ)
331			ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
332	}
333
334	if (pt->destroy_self)
335		lws_context_destroy(pt->context);
336}
337
338static void
339elops_run_pt_ev(struct lws_context *context, int tsi)
340{
341	if (pt_to_priv_ev(&context->pt[tsi])->io_loop)
342		ev_run(pt_to_priv_ev(&context->pt[tsi])->io_loop, 0);
343}
344
345static int
346elops_destroy_context2_ev(struct lws_context *context)
347{
348	struct lws_context_per_thread *pt;
349	struct lws_pt_eventlibs_libev *ptpr;
350	int n, m;
351
352	for (n = 0; n < context->count_threads; n++) {
353		int budget = 1000;
354
355		pt = &context->pt[n];
356		ptpr = pt_to_priv_ev(pt);
357
358		/* only for internal loops... */
359
360		if (pt->event_loop_foreign || !ptpr->io_loop)
361			continue;
362
363		if (!context->evlib_finalize_destroy_after_int_loops_stop) {
364			ev_break(ptpr->io_loop, EVBREAK_ONE);
365			continue;
366		}
367		while (budget-- &&
368		       (m = ev_run(ptpr->io_loop, 0)))
369			;
370
371		ev_loop_destroy(ptpr->io_loop);
372	}
373
374	return 0;
375}
376
377static int
378elops_init_vhost_listen_wsi_ev(struct lws *wsi)
379{
380	struct lws_wsi_eventlibs_libev *w;
381	int fd;
382
383	if (!wsi) {
384		assert(0);
385		return 0;
386	}
387
388	w = wsi_to_priv_ev(wsi);
389	w->w_read.context = wsi->a.context;
390	w->w_write.context = wsi->a.context;
391
392	if (wsi->role_ops->file_handle)
393		fd = wsi->desc.filefd;
394	else
395		fd = wsi->desc.sockfd;
396
397	ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
398	//ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
399
400	elops_io_ev(wsi, LWS_EV_START | LWS_EV_READ);
401
402	return 0;
403}
404
405static void
406elops_destroy_wsi_ev(struct lws *wsi)
407{
408	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
409	struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
410	struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
411
412	ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
413	ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
414}
415
416static const struct lws_event_loop_ops event_loop_ops_ev = {
417	/* name */			"libev",
418	/* init_context */		elops_init_context_ev,
419	/* destroy_context1 */		NULL,
420	/* destroy_context2 */		elops_destroy_context2_ev,
421	/* init_vhost_listen_wsi */	elops_init_vhost_listen_wsi_ev,
422	/* init_pt */			elops_init_pt_ev,
423	/* wsi_logical_close */		NULL,
424	/* check_client_connect_ok */	NULL,
425	/* close_handle_manually */	NULL,
426	/* accept */			elops_accept_ev,
427	/* io */			elops_io_ev,
428	/* run_pt */			elops_run_pt_ev,
429	/* destroy_pt */		elops_destroy_pt_ev,
430	/* destroy wsi */		elops_destroy_wsi_ev,
431	/* foreign_thread */		NULL,
432
433	/* flags */			0,
434
435	/* evlib_size_ctx */	0,
436	/* evlib_size_pt */	sizeof(struct lws_pt_eventlibs_libev),
437	/* evlib_size_vh */	sizeof(struct lws_vh_eventlibs_libev),
438	/* evlib_size_wsi */	sizeof(struct lws_wsi_eventlibs_libev),
439};
440
441#if defined(LWS_WITH_EVLIB_PLUGINS)
442LWS_VISIBLE
443#endif
444const lws_plugin_evlib_t evlib_ev = {
445	.hdr = {
446		"libev event loop",
447		"lws_evlib_plugin",
448		LWS_BUILD_HASH,
449		LWS_PLUGIN_API_MAGIC
450	},
451
452	.ops	= &event_loop_ops_ev
453};
454