1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2021 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-libuv.h" 27 28#define pt_to_priv_uv(_pt) ((struct lws_pt_eventlibs_libuv *)(_pt)->evlib_pt) 29#define wsi_to_priv_uv(_w) ((struct lws_wsi_eventlibs_libuv *)(_w)->evlib_wsi) 30 31static void 32lws_uv_sultimer_cb(uv_timer_t *timer 33#if UV_VERSION_MAJOR == 0 34 , int status 35#endif 36) 37{ 38 struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(timer, 39 struct lws_pt_eventlibs_libuv, sultimer); 40 struct lws_context_per_thread *pt = ptpr->pt; 41 lws_usec_t us; 42 43 lws_context_lock(pt->context, __func__); 44 lws_pt_lock(pt, __func__); 45 us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, 46 lws_now_usecs()); 47 if (us) 48 uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb, 49 LWS_US_TO_MS((uint64_t)us), 0); 50 lws_pt_unlock(pt); 51 lws_context_unlock(pt->context); 52} 53 54static void 55lws_uv_idle(uv_idle_t *handle 56#if UV_VERSION_MAJOR == 0 57 , int status 58#endif 59) 60{ struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(handle, 61 struct lws_pt_eventlibs_libuv, idle); 62 struct lws_context_per_thread *pt = ptpr->pt; 63 lws_usec_t us; 64 65 lws_service_do_ripe_rxflow(pt); 66 67 lws_context_lock(pt->context, __func__); 68 lws_pt_lock(pt, __func__); 69 70 /* 71 * is there anybody with pending stuff that needs service forcing? 72 */ 73 if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) 74 /* -1 timeout means just do forced service */ 75 _lws_plat_service_forced_tsi(pt->context, pt->tid); 76 77 /* account for sultimer */ 78 79 us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, 80 lws_now_usecs()); 81 if (us) 82 uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb, 83 LWS_US_TO_MS((uint64_t)us), 0); 84 85 /* if there is nobody who needs service forcing, shut down idle */ 86 if (lws_service_adjust_timeout(pt->context, 1, pt->tid)) 87 uv_idle_stop(handle); 88 89 lws_pt_unlock(pt); 90 lws_context_unlock(pt->context); 91} 92 93static void 94lws_io_cb(uv_poll_t *watcher, int status, int revents) 95{ 96 struct lws *wsi = (struct lws *)((uv_handle_t *)watcher)->data; 97 struct lws_context *context = wsi->a.context; 98 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 99 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 100 struct lws_pollfd eventfd; 101 102 lws_context_lock(pt->context, __func__); 103 lws_pt_lock(pt, __func__); 104 105 if (pt->is_destroyed) 106 goto bail; 107 108 if (!ptpriv->thread_valid) { 109 /* record the thread id that gave us our first event */ 110 ptpriv->uv_thread = uv_thread_self(); 111 ptpriv->thread_valid = 1; 112 } 113 114#if defined(WIN32) || defined(_WIN32) 115 eventfd.fd = watcher->socket; 116#else 117 eventfd.fd = watcher->io_watcher.fd; 118#endif 119 eventfd.events = 0; 120 eventfd.revents = 0; 121 122 if (status < 0) { 123 /* 124 * At this point status will be an UV error, like UV_EBADF, 125 * we treat all errors as LWS_POLLHUP 126 * 127 * You might want to return; instead of servicing the fd in 128 * some cases */ 129 if (status == UV_EAGAIN) 130 goto bail; 131 132 eventfd.events |= LWS_POLLHUP; 133 eventfd.revents |= LWS_POLLHUP; 134 } else { 135 if (revents & UV_READABLE) { 136 eventfd.events |= LWS_POLLIN; 137 eventfd.revents |= LWS_POLLIN; 138 } 139 if (revents & UV_WRITABLE) { 140 eventfd.events |= LWS_POLLOUT; 141 eventfd.revents |= LWS_POLLOUT; 142 } 143 } 144 145 lws_pt_unlock(pt); 146 lws_context_unlock(pt->context); 147 148 lws_service_fd_tsi(context, &eventfd, wsi->tsi); 149 150 if (pt->destroy_self) { 151 lws_context_destroy(pt->context); 152 return; 153 } 154 155 uv_idle_start(&ptpriv->idle, lws_uv_idle); 156 return; 157 158bail: 159 lws_pt_unlock(pt); 160 lws_context_unlock(pt->context); 161} 162 163/* 164 * This does not actually stop the event loop. The reason is we have to pass 165 * libuv handle closures through its event loop. So this tries to close all 166 * wsi, and set a flag; when all the wsi closures are finalized then we 167 * actually stop the libuv event loops. 168 */ 169static void 170lws_libuv_stop(struct lws_context *context) 171{ 172 if (context->requested_stop_internal_loops) { 173 lwsl_cx_err(context, "ignoring"); 174 return; 175 } 176 177 context->requested_stop_internal_loops = 1; 178 lws_context_destroy(context); 179} 180 181static void 182lws_uv_signal_handler(uv_signal_t *watcher, int signum) 183{ 184 struct lws_context_per_thread *pt = (struct lws_context_per_thread *) 185 watcher->data; 186 187 if (pt->context->eventlib_signal_cb) { 188 pt->context->eventlib_signal_cb((void *)watcher, signum); 189 190 return; 191 } 192 193 lwsl_cx_err(pt->context, "internal signal handler caught signal %d", 194 signum); 195 lws_libuv_stop(pt->context); 196} 197 198static int 199lws_uv_finalize_pt(struct lws_context_per_thread *pt) 200{ 201 pt->event_loop_pt_unused = 1; 202 203 lwsl_cx_info(pt->context, "thr %d", (int)(pt - pt->context->pt)); 204 205 lws_context_lock(pt->context, __func__); 206 207 if (!--pt->context->undestroyed_threads) { 208 struct lws_vhost *vh = pt->context->vhost_list; 209 210 /* 211 * eventually, we emptied all the pts... 212 */ 213 214 lwsl_cx_debug(pt->context, "all pts down now"); 215 216 /* protocols may have initialized libuv objects */ 217 218 while (vh) { 219 lws_vhost_destroy1(vh); 220 vh = vh->vhost_next; 221 } 222 223 if (!pt->count_event_loop_static_asset_handles && 224 pt->event_loop_foreign) { 225 lwsl_cx_info(pt->context, "resuming context_destroy"); 226 lws_context_unlock(pt->context); 227 lws_context_destroy(pt->context); 228 /* 229 * For foreign, we're being called from the foreign 230 * thread context the loop is associated with, we must 231 * return to it cleanly even though we are done with it. 232 */ 233 return 1; 234 } 235 } else 236 lwsl_cx_debug(pt->context, "still %d undestroyed", 237 pt->context->undestroyed_threads); 238 239 lws_context_unlock(pt->context); 240 241 return 0; 242} 243 244// static void lws_uv_walk_cb(uv_handle_t *handle, void *arg) 245// { 246// if (!uv_is_closing(handle)) 247// lwsl_err("%s: handle %p still alive on loop\n", __func__, handle); 248// } 249 250 251static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP }; 252 253/* 254 * Closing Phase 2: Close callback for a static UV asset 255 */ 256 257static void 258lws_uv_close_cb_sa(uv_handle_t *handle) 259{ 260 struct lws_context_per_thread *pt = 261 LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(handle); 262 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 263 struct lws_context *context = pt->context; 264#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG) 265 int tsi = (int)(pt - &context->pt[0]); 266#endif 267 268 lwsl_cx_info(context, "thr %d: sa left %d: dyn left: %d (rk %d)", 269 tsi, 270 pt->count_event_loop_static_asset_handles - 1, 271 ptpriv->extant_handles, 272 context->requested_stop_internal_loops); 273 274 /* any static assets left? */ 275 276 if (LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(handle) || 277 ptpriv->extant_handles) 278 return; 279 280 /* 281 * So we believe nothing of ours left on the loop. Let's sanity 282 * check it to count what's still on the loop 283 */ 284 285 // uv_walk(pt_to_priv_uv(pt)->io_loop, lws_uv_walk_cb, NULL); 286 287 /* 288 * That's it... all wsi were down, and now every 289 * static asset lws had a UV handle for is down. 290 * 291 * Stop the loop so we can get out of here. 292 */ 293 294 lwsl_cx_info(context, "thr %d: seen final static handle gone", tsi); 295 296 if (!pt->event_loop_foreign) 297 lws_context_destroy(context); 298 299 lws_uv_finalize_pt(pt); 300 301 lwsl_cx_info(context, "all done"); 302} 303 304/* 305 * These must be called by protocols that want to use libuv objects directly... 306 * 307 * .... when the libuv object is created... 308 */ 309 310void 311lws_libuv_static_refcount_add(uv_handle_t *h, struct lws_context *context, 312 int tsi) 313{ 314 struct lws_context_per_thread *pt = &context->pt[tsi]; 315 316 LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(h, pt); 317} 318 319/* 320 * ... and in the close callback when the object is closed. 321 */ 322 323void 324lws_libuv_static_refcount_del(uv_handle_t *h) 325{ 326 lws_uv_close_cb_sa(h); 327} 328 329void 330lws_libuv_stop_without_kill(const struct lws_context *context, int tsi) 331{ 332 if (pt_to_priv_uv(&context->pt[tsi])->io_loop) 333 uv_stop(pt_to_priv_uv(&context->pt[tsi])->io_loop); 334} 335 336uv_loop_t * 337lws_uv_getloop(struct lws_context *context, int tsi) 338{ 339 if (pt_to_priv_uv(&context->pt[tsi])->io_loop) 340 return pt_to_priv_uv(&context->pt[tsi])->io_loop; 341 342 return NULL; 343} 344 345int 346lws_libuv_check_watcher_active(struct lws *wsi) 347{ 348 uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher; 349 350 if (!h) 351 return 0; 352 353 return uv_is_active(h); 354} 355 356static int 357elops_init_context_uv(struct lws_context *context, 358 const struct lws_context_creation_info *info) 359{ 360 int n; 361 362 context->eventlib_signal_cb = info->signal_cb; 363 364 for (n = 0; n < context->count_threads; n++) 365 pt_to_priv_uv(&context->pt[n])->w_sigint.context = context; 366 367 return 0; 368} 369 370static int 371elops_destroy_context1_uv(struct lws_context *context) 372{ 373 struct lws_context_per_thread *pt; 374 int n, m = 0; 375 376 for (n = 0; n < context->count_threads; n++) { 377 int budget = 10000; 378 pt = &context->pt[n]; 379 380 /* only for internal loops... */ 381 382 if (!pt->event_loop_foreign) { 383 384 while (budget-- && (m = uv_run(pt_to_priv_uv(pt)->io_loop, 385 UV_RUN_NOWAIT))) 386 ; 387 if (m) 388 lwsl_cx_info(context, "tsi %d: unclosed", n); 389 390 } 391 } 392 393 /* call destroy2 if internal loop */ 394 return !context->pt[0].event_loop_foreign; 395} 396 397static int 398elops_destroy_context2_uv(struct lws_context *context) 399{ 400 struct lws_context_per_thread *pt; 401 int n, internal = 0; 402 403 for (n = 0; n < context->count_threads; n++) { 404 pt = &context->pt[n]; 405 406 /* only for internal loops... */ 407 408 if (!pt->event_loop_foreign && pt_to_priv_uv(pt)->io_loop) { 409 internal = 1; 410 if (!context->evlib_finalize_destroy_after_int_loops_stop) 411 uv_stop(pt_to_priv_uv(pt)->io_loop); 412 else { 413#if UV_VERSION_MAJOR > 0 414 uv_loop_close(pt_to_priv_uv(pt)->io_loop); 415#endif 416 lws_free_set_NULL(pt_to_priv_uv(pt)->io_loop); 417 } 418 } 419 } 420 421 return internal; 422} 423 424static int 425elops_wsi_logical_close_uv(struct lws *wsi) 426{ 427 if (!lws_socket_is_valid(wsi->desc.sockfd) && 428 wsi->role_ops && strcmp(wsi->role_ops->name, "raw-file") && 429 !wsi_to_priv_uv(wsi)->w_read.pwatcher) 430 return 0; 431 432 if (wsi->listener || wsi->event_pipe) { 433 lwsl_wsi_debug(wsi, "%d %d stop listener / pipe poll", 434 wsi->listener, 435 wsi->event_pipe); 436 if (wsi_to_priv_uv(wsi)->w_read.pwatcher) 437 uv_poll_stop(wsi_to_priv_uv(wsi)->w_read.pwatcher); 438 } 439 lwsl_wsi_debug(wsi, "lws_libuv_closehandle"); 440 /* 441 * libuv has to do his own close handle processing asynchronously 442 */ 443 lws_libuv_closehandle(wsi); 444 445 return 1; /* do not complete the wsi close, uv close cb will do it */ 446} 447 448static int 449elops_check_client_connect_ok_uv(struct lws *wsi) 450{ 451 if (lws_libuv_check_watcher_active(wsi)) { 452 lwsl_wsi_warn(wsi, "Waiting for libuv watcher to close"); 453 return 1; 454 } 455 456 return 0; 457} 458 459static void 460lws_libuv_closewsi_m(uv_handle_t* handle) 461{ 462 lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data; 463 464 lwsl_debug("%s: sockfd %d\n", __func__, sockfd); 465 compatible_close(sockfd); 466 lws_free(handle); 467} 468 469static void 470elops_close_handle_manually_uv(struct lws *wsi) 471{ 472 uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher; 473 474 lwsl_wsi_debug(wsi, "lws_libuv_closehandle"); 475 476 /* 477 * the "manual" variant only closes the handle itself and the 478 * related fd. handle->data is the fd. 479 */ 480 h->data = (void *)(lws_intptr_t)wsi->desc.sockfd; 481 482 /* 483 * We take responsibility to close / destroy these now. 484 * Remove any trace from the wsi. 485 */ 486 487 wsi->desc.sockfd = LWS_SOCK_INVALID; 488 wsi_to_priv_uv(wsi)->w_read.pwatcher = NULL; 489 wsi->told_event_loop_closed = 1; 490 491 uv_close(h, lws_libuv_closewsi_m); 492} 493 494static int 495elops_accept_uv(struct lws *wsi) 496{ 497 struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 498 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 499 struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read; 500 int n; 501 502 if (!ptpriv->thread_valid) { 503 /* record the thread id that gave us our first event */ 504 ptpriv->uv_thread = uv_thread_self(); 505 ptpriv->thread_valid = 1; 506 } 507 508 w_read->context = wsi->a.context; 509 510 w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh"); 511 if (!w_read->pwatcher) 512 return -1; 513 514 if (wsi->role_ops->file_handle) 515 n = uv_poll_init(pt_to_priv_uv(pt)->io_loop, w_read->pwatcher, 516 (int)(lws_intptr_t)wsi->desc.filefd); 517 else 518 n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop, 519 w_read->pwatcher, wsi->desc.sockfd); 520 521 if (n) { 522 lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n, 523 (void *)(lws_intptr_t)wsi->desc.sockfd); 524 lws_free(w_read->pwatcher); 525 w_read->pwatcher = NULL; 526 return -1; 527 } 528 529 ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi; 530 531 ptpriv->extant_handles++; 532 533 lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d", 534 (int)(pt - &pt->context->pt[0]), 535 pt->count_event_loop_static_asset_handles, 536 ptpriv->extant_handles); 537 538 return 0; 539} 540 541static void 542elops_io_uv(struct lws *wsi, unsigned int flags) 543{ 544 struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 545 struct lws_io_watcher_libuv *w = &(wsi_to_priv_uv(wsi)->w_read); 546 int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE); 547 548 lwsl_wsi_debug(wsi, "%d", flags); 549 550 /* w->context is set after the loop is initialized */ 551 552 if (!pt_to_priv_uv(pt)->io_loop || !w->context) { 553 lwsl_wsi_info(wsi, "no io loop yet"); 554 return; 555 } 556 557 if (!((flags & (LWS_EV_START | LWS_EV_STOP)) && 558 (flags & (LWS_EV_READ | LWS_EV_WRITE)))) { 559 lwsl_wsi_err(wsi, "assert: flags %d", flags); 560 assert(0); 561 } 562 563 if (!w->pwatcher || wsi->told_event_loop_closed) { 564 lwsl_wsi_info(wsi, "no watcher"); 565 566 return; 567 } 568 569 if (flags & LWS_EV_START) { 570 if (flags & LWS_EV_WRITE) 571 current_events |= UV_WRITABLE; 572 573 if (flags & LWS_EV_READ) 574 current_events |= UV_READABLE; 575 576 uv_poll_start(w->pwatcher, current_events, lws_io_cb); 577 } else { 578 if (flags & LWS_EV_WRITE) 579 current_events &= ~UV_WRITABLE; 580 581 if (flags & LWS_EV_READ) 582 current_events &= ~UV_READABLE; 583 584 if (!(current_events & (UV_READABLE | UV_WRITABLE))) 585 uv_poll_stop(w->pwatcher); 586 else 587 uv_poll_start(w->pwatcher, current_events, lws_io_cb); 588 } 589 590 w->actual_events = (uint8_t)current_events; 591} 592 593static int 594elops_init_vhost_listen_wsi_uv(struct lws *wsi) 595{ 596 struct lws_context_per_thread *pt; 597 struct lws_pt_eventlibs_libuv *ptpriv; 598 struct lws_io_watcher_libuv *w_read; 599 int n; 600 601 if (!wsi) 602 return 0; 603 604 w_read = &wsi_to_priv_uv(wsi)->w_read; 605 606 if (w_read->context) 607 return 0; 608 609 pt = &wsi->a.context->pt[(int)wsi->tsi]; 610 ptpriv = pt_to_priv_uv(pt); 611 if (!ptpriv->io_loop) 612 return 0; 613 614 w_read->context = wsi->a.context; 615 616 w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh"); 617 if (!w_read->pwatcher) 618 return -1; 619 620 n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop, 621 w_read->pwatcher, wsi->desc.sockfd); 622 if (n) { 623 lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n, 624 (void *)(lws_intptr_t)wsi->desc.sockfd); 625 626 return -1; 627 } 628 629 ptpriv->extant_handles++; 630 631 lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d", 632 (int)(pt - &pt->context->pt[0]), 633 pt->count_event_loop_static_asset_handles, 634 ptpriv->extant_handles); 635 636 ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi; 637 638 elops_io_uv(wsi, LWS_EV_START | LWS_EV_READ); 639 640 return 0; 641} 642 643static void 644elops_run_pt_uv(struct lws_context *context, int tsi) 645{ 646 if (pt_to_priv_uv(&context->pt[tsi])->io_loop) 647 uv_run(pt_to_priv_uv(&context->pt[tsi])->io_loop, 0); 648} 649 650static void 651elops_destroy_pt_uv(struct lws_context *context, int tsi) 652{ 653 struct lws_context_per_thread *pt = &context->pt[tsi]; 654 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 655 int m, ns; 656 657 if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)) 658 return; 659 660 if (!ptpriv->io_loop) 661 return; 662 663 if (pt->event_loop_destroy_processing_done) { 664 if (!pt->event_loop_foreign) { 665 lwsl_warn("%s: stopping event loop\n", __func__); 666 uv_stop(pt_to_priv_uv(pt)->io_loop); 667 } 668 return; 669 } 670 671 pt->event_loop_destroy_processing_done = 1; 672 // lwsl_cx_debug(context, "%d", tsi); 673 674 if (!pt->event_loop_foreign) { 675 676 uv_signal_stop(&pt_to_priv_uv(pt)->w_sigint.watcher); 677 678 ns = LWS_ARRAY_SIZE(sigs); 679 if (lws_check_opt(context->options, 680 LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN)) 681 ns = 2; 682 683 for (m = 0; m < ns; m++) { 684 uv_signal_stop(&pt_to_priv_uv(pt)->signals[m]); 685 uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->signals[m], 686 lws_uv_close_cb_sa); 687 } 688 } else 689 lwsl_cx_debug(context, "not closing pt signals"); 690 691 uv_timer_stop(&pt_to_priv_uv(pt)->sultimer); 692 uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->sultimer, lws_uv_close_cb_sa); 693 694 uv_idle_stop(&pt_to_priv_uv(pt)->idle); 695 uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->idle, lws_uv_close_cb_sa); 696} 697 698static int 699elops_listen_init_uv(struct lws_dll2 *d, void *user) 700{ 701 struct lws *wsi = lws_container_of(d, struct lws, listen_list); 702 703 if (elops_init_vhost_listen_wsi_uv(wsi) == -1) 704 return -1; 705 706 return 0; 707} 708 709/* 710 * This needs to be called after vhosts have been defined. 711 * 712 * If later, after server start, another vhost is added, this must be 713 * called again to bind the vhost 714 */ 715 716int 717elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) 718{ 719 struct lws_context_per_thread *pt = &context->pt[tsi]; 720 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 721 int status = 0, n, ns, first = 1; 722 uv_loop_t *loop = (uv_loop_t *)_loop; 723 724 ptpriv->pt = pt; 725 726 if (!ptpriv->io_loop) { 727 if (!loop) { 728 loop = lws_malloc(sizeof(*loop), "libuv loop"); 729 if (!loop) { 730 lwsl_cx_err(context, "OOM"); 731 return -1; 732 } 733#if UV_VERSION_MAJOR > 0 734 uv_loop_init(loop); 735#else 736 lwsl_cx_err(context, "This libuv is too old to work..."); 737 return 1; 738#endif 739 pt->event_loop_foreign = 0; 740 } else { 741 lwsl_cx_notice(context, " Using foreign event loop..."); 742 pt->event_loop_foreign = 1; 743 } 744 745 ptpriv->io_loop = loop; 746 uv_idle_init(loop, &ptpriv->idle); 747 LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->idle, pt); 748 uv_idle_start(&ptpriv->idle, lws_uv_idle); 749 750 ns = LWS_ARRAY_SIZE(sigs); 751 if (lws_check_opt(context->options, 752 LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN)) 753 ns = 2; 754 755 if (!pt->event_loop_foreign) { 756 assert(ns <= (int)LWS_ARRAY_SIZE(ptpriv->signals)); 757 for (n = 0; n < ns; n++) { 758 uv_signal_init(loop, &ptpriv->signals[n]); 759 LWS_UV_REFCOUNT_STATIC_HANDLE_NEW( 760 &ptpriv->signals[n], pt); 761 ptpriv->signals[n].data = pt; 762 uv_signal_start(&ptpriv->signals[n], 763 lws_uv_signal_handler, sigs[n]); 764 } 765 } 766 } else 767 first = 0; 768 769 /* 770 * Initialize the accept wsi read watcher with all the listening sockets 771 * and register a callback for read operations 772 * 773 * We have to do it here because the uv loop(s) are not 774 * initialized until after context creation. 775 */ 776 lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_uv); 777 778 if (!first) 779 return status; 780 781 uv_timer_init(ptpriv->io_loop, &ptpriv->sultimer); 782 LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->sultimer, pt); 783 784 return status; 785} 786 787static void 788lws_libuv_closewsi(uv_handle_t* handle) 789{ 790 struct lws *wsi = (struct lws *)handle->data; 791 struct lws_context *context = lws_get_context(wsi); 792 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 793 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 794#if defined(LWS_WITH_SERVER) 795 int lspd = 0; 796#endif 797 798 // lwsl_wsi_notice(wsi, "in"); 799 800 lws_context_lock(context, __func__); 801 802 /* 803 * We get called back here for every wsi that closes 804 */ 805 806#if defined(LWS_WITH_SERVER) 807 if (wsi->role_ops && !strcmp(wsi->role_ops->name, "listen") && 808 wsi->a.context->deprecated) { 809 lspd = 1; 810 context->deprecation_pending_listen_close_count--; 811 if (!context->deprecation_pending_listen_close_count) 812 lspd = 2; 813 } 814#endif 815 816 lws_pt_lock(pt, __func__); 817 818 lwsl_wsi_info(wsi, "thr %d: sa left %d: dyn left: %d (rk %d)", 819 (int)(pt - &pt->context->pt[0]), 820 pt->count_event_loop_static_asset_handles, 821 ptpriv->extant_handles - 1, 822 context->requested_stop_internal_loops); 823 824 __lws_close_free_wsi_final(wsi); 825 assert(ptpriv->extant_handles); 826 ptpriv->extant_handles--; 827 lws_pt_unlock(pt); 828 829 /* it's our job to close the handle finally */ 830 lws_free(handle); 831 832#if defined(LWS_WITH_SERVER) 833 if (lspd == 2 && context->deprecation_cb) { 834 lwsl_cx_notice(context, "calling deprecation callback"); 835 context->deprecation_cb(); 836 } 837#endif 838 839 /* 840 * eventually, we closed all the wsi... 841 */ 842 843 if (context->requested_stop_internal_loops && 844 !ptpriv->extant_handles && 845 !pt->count_event_loop_static_asset_handles) { 846 847 /* 848 * we closed everything on this pt 849 */ 850 851 lws_context_unlock(context); 852 lws_uv_finalize_pt(pt); 853 854 return; 855 } 856 857 lws_context_unlock(context); 858} 859 860void 861lws_libuv_closehandle(struct lws *wsi) 862{ 863 uv_handle_t* handle; 864 struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read; 865 866 if (!w_read->pwatcher) 867 return; 868 869 if (wsi->told_event_loop_closed) 870 return; 871 872// lwsl_wsi_debug(wsi, "in"); 873 874 wsi->told_event_loop_closed = 1; 875 876 /* 877 * The normal close path attaches the related wsi as the 878 * handle->data. 879 */ 880 881 handle = (uv_handle_t *)w_read->pwatcher; 882 883 /* ensure we can only do this once */ 884 885 w_read->pwatcher = NULL; 886 887 uv_close(handle, lws_libuv_closewsi); 888} 889 890static int 891elops_foreign_thread_uv(struct lws_context *cx, int tsi) 892{ 893 struct lws_context_per_thread *pt = &cx->pt[tsi]; 894 struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); 895 uv_thread_t th = uv_thread_self(); 896 897 if (!ptpriv->thread_valid) 898 /* 899 * We can't judge it until we get the first event from the loop 900 */ 901 return 0; 902 903 /* 904 * This is the same thread that gave us the first event on this loop? 905 * Return 0 if so. 906 */ 907 908 return !uv_thread_equal(&th, &ptpriv->uv_thread); 909} 910 911static const struct lws_event_loop_ops event_loop_ops_uv = { 912 /* name */ "libuv", 913 /* init_context */ elops_init_context_uv, 914 /* destroy_context1 */ elops_destroy_context1_uv, 915 /* destroy_context2 */ elops_destroy_context2_uv, 916 /* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_uv, 917 /* init_pt */ elops_init_pt_uv, 918 /* wsi_logical_close */ elops_wsi_logical_close_uv, 919 /* check_client_connect_ok */ elops_check_client_connect_ok_uv, 920 /* close_handle_manually */ elops_close_handle_manually_uv, 921 /* accept */ elops_accept_uv, 922 /* io */ elops_io_uv, 923 /* run_pt */ elops_run_pt_uv, 924 /* destroy_pt */ elops_destroy_pt_uv, 925 /* destroy wsi */ NULL, 926 /* foreign_thread */ elops_foreign_thread_uv, 927 928 /* flags */ 0, 929 930 /* evlib_size_ctx */ sizeof(struct lws_context_eventlibs_libuv), 931 /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_libuv), 932 /* evlib_size_vh */ 0, 933 /* evlib_size_wsi */ sizeof(struct lws_io_watcher_libuv), 934}; 935 936#if defined(LWS_WITH_EVLIB_PLUGINS) 937LWS_VISIBLE 938#endif 939const lws_plugin_evlib_t evlib_uv = { 940 .hdr = { 941 "libuv event loop", 942 "lws_evlib_plugin", 943 LWS_BUILD_HASH, 944 LWS_PLUGIN_API_MAGIC 945 }, 946 947 .ops = &event_loop_ops_uv 948}; 949 950