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