• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 static void
lws_ev_hrtimer_cb(struct ev_loop * loop,struct ev_timer * watcher,int revents)33 lws_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 
50 static void
lws_ev_idle_cb(struct ev_loop * loop,struct ev_idle * handle,int revents)51 lws_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 
87 static void
lws_accept_cb(struct ev_loop * loop,struct ev_io * watcher,int revents)88 lws_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 
123 void
lws_ev_sigint_cb(struct ev_loop * loop,struct ev_signal * watcher,int revents)124 lws_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 
136 static int
elops_listen_init_ev(struct lws_dll2 * d,void * user)137 elops_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 
157 static int
elops_init_pt_ev(struct lws_context * context,void * _loop,int tsi)158 elops_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 
240 static int
elops_listen_destroy_ev(struct lws_dll2 * d,void * user)241 elops_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 
254 static void
elops_destroy_pt_ev(struct lws_context * context,int tsi)255 elops_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 
271 static int
elops_init_context_ev(struct lws_context * context,const struct lws_context_creation_info * info)272 elops_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 
285 static int
elops_accept_ev(struct lws * wsi)286 elops_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 
305 static void
elops_io_ev(struct lws * wsi,unsigned int flags)306 elops_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 
338 static void
elops_run_pt_ev(struct lws_context * context,int tsi)339 elops_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 
345 static int
elops_destroy_context2_ev(struct lws_context * context)346 elops_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 
377 static int
elops_init_vhost_listen_wsi_ev(struct lws * wsi)378 elops_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 
405 static void
elops_destroy_wsi_ev(struct lws * wsi)406 elops_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 
416 static 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)
442 LWS_VISIBLE
443 #endif
444 const 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