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