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