1 /* $NetBSD: loop.c,v 1.3 2025/05/21 14:48:04 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <stdlib.h> 17 #include <sys/types.h> 18 #include <unistd.h> 19 20 #include <isc/async.h> 21 #include <isc/atomic.h> 22 #include <isc/barrier.h> 23 #include <isc/condition.h> 24 #include <isc/job.h> 25 #include <isc/list.h> 26 #include <isc/log.h> 27 #include <isc/loop.h> 28 #include <isc/magic.h> 29 #include <isc/mem.h> 30 #include <isc/mutex.h> 31 #include <isc/refcount.h> 32 #include <isc/result.h> 33 #include <isc/signal.h> 34 #include <isc/strerr.h> 35 #include <isc/thread.h> 36 #include <isc/tid.h> 37 #include <isc/time.h> 38 #include <isc/urcu.h> 39 #include <isc/util.h> 40 #include <isc/uv.h> 41 #include <isc/work.h> 42 43 #include "async_p.h" 44 #include "job_p.h" 45 #include "loop_p.h" 46 47 /** 48 * Private 49 */ 50 51 thread_local isc_loop_t *isc__loop_local = NULL; 52 53 static void 54 ignore_signal(int sig, void (*handler)(int)) { 55 struct sigaction sa = { .sa_handler = handler }; 56 57 if (sigfillset(&sa.sa_mask) != 0 || sigaction(sig, &sa, NULL) < 0) { 58 FATAL_SYSERROR(errno, "ignore_signal(%d)", sig); 59 } 60 } 61 62 void 63 isc_loopmgr_shutdown(isc_loopmgr_t *loopmgr) { 64 if (!atomic_compare_exchange_strong(&loopmgr->shuttingdown, 65 &(bool){ false }, true)) 66 { 67 return; 68 } 69 70 for (size_t i = 0; i < loopmgr->nloops; i++) { 71 isc_loop_t *loop = &loopmgr->loops[i]; 72 int r; 73 74 r = uv_async_send(&loop->shutdown_trigger); 75 UV_RUNTIME_CHECK(uv_async_send, r); 76 } 77 } 78 79 static void 80 isc__loopmgr_signal(void *arg, int signum) { 81 isc_loopmgr_t *loopmgr = (isc_loopmgr_t *)arg; 82 83 switch (signum) { 84 case SIGINT: 85 case SIGTERM: 86 isc_loopmgr_shutdown(loopmgr); 87 break; 88 default: 89 UNREACHABLE(); 90 } 91 } 92 93 static void 94 pause_loop(isc_loop_t *loop) { 95 isc_loopmgr_t *loopmgr = loop->loopmgr; 96 97 rcu_thread_offline(); 98 99 loop->paused = true; 100 (void)isc_barrier_wait(&loopmgr->pausing); 101 } 102 103 static void 104 resume_loop(isc_loop_t *loop) { 105 isc_loopmgr_t *loopmgr = loop->loopmgr; 106 107 (void)isc_barrier_wait(&loopmgr->resuming); 108 loop->paused = false; 109 110 rcu_thread_online(); 111 } 112 113 static void 114 pauseresume_cb(uv_async_t *handle) { 115 isc_loop_t *loop = uv_handle_get_data(handle); 116 117 pause_loop(loop); 118 resume_loop(loop); 119 } 120 121 #define XX(uc, lc) \ 122 case UV_##uc: \ 123 fprintf(stderr, "%s, %s: dangling %p: %p.type = %s\n", \ 124 __func__, (char *)arg, handle->loop, handle, #lc); \ 125 break; 126 127 static void 128 loop_walk_cb(uv_handle_t *handle, void *arg) { 129 if (uv_is_closing(handle)) { 130 return; 131 } 132 133 switch (handle->type) { 134 UV_HANDLE_TYPE_MAP(XX) 135 default: 136 fprintf(stderr, "%s, %s: dangling %p: %p.type = %s\n", __func__, 137 (char *)arg, &handle->loop, handle, "unknown"); 138 } 139 } 140 141 static void 142 shutdown_trigger_close_cb(uv_handle_t *handle) { 143 isc_loop_t *loop = uv_handle_get_data(handle); 144 145 isc_loop_detach(&loop); 146 } 147 148 static void 149 destroy_cb(uv_async_t *handle) { 150 isc_loop_t *loop = uv_handle_get_data(handle); 151 152 /* Again, the first close callback here is called last */ 153 uv_close(&loop->async_trigger, isc__async_close); 154 uv_close(&loop->run_trigger, isc__job_close); 155 uv_close(&loop->destroy_trigger, NULL); 156 uv_close(&loop->pause_trigger, NULL); 157 uv_close(&loop->quiescent, NULL); 158 159 uv_walk(&loop->loop, loop_walk_cb, (char *)"destroy_cb"); 160 } 161 162 static void 163 shutdown_cb(uv_async_t *handle) { 164 isc_loop_t *loop = uv_handle_get_data(handle); 165 isc_loopmgr_t *loopmgr = loop->loopmgr; 166 167 /* Make sure, we can't be called again */ 168 uv_close(&loop->shutdown_trigger, shutdown_trigger_close_cb); 169 170 /* Mark this loop as shutting down */ 171 loop->shuttingdown = true; 172 173 if (DEFAULT_LOOP(loopmgr) == CURRENT_LOOP(loopmgr)) { 174 /* Stop the signal handlers */ 175 isc_signal_stop(loopmgr->sigterm); 176 isc_signal_stop(loopmgr->sigint); 177 178 /* Free the signal handlers */ 179 isc_signal_destroy(&loopmgr->sigterm); 180 isc_signal_destroy(&loopmgr->sigint); 181 } 182 183 enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking( 184 &loop->async_jobs.head, &loop->async_jobs.tail, 185 &loop->teardown_jobs.head, &loop->teardown_jobs.tail); 186 INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK); 187 int r = uv_async_send(&loop->async_trigger); 188 UV_RUNTIME_CHECK(uv_async_send, r); 189 } 190 191 static void 192 loop_init(isc_loop_t *loop, isc_loopmgr_t *loopmgr, uint32_t tid, 193 const char *kind) { 194 *loop = (isc_loop_t){ 195 .tid = tid, 196 .loopmgr = loopmgr, 197 .run_jobs = ISC_LIST_INITIALIZER, 198 }; 199 200 __cds_wfcq_init(&loop->async_jobs.head, &loop->async_jobs.tail); 201 __cds_wfcq_init(&loop->setup_jobs.head, &loop->setup_jobs.tail); 202 __cds_wfcq_init(&loop->teardown_jobs.head, &loop->teardown_jobs.tail); 203 204 int r = uv_loop_init(&loop->loop); 205 UV_RUNTIME_CHECK(uv_loop_init, r); 206 207 r = uv_async_init(&loop->loop, &loop->pause_trigger, pauseresume_cb); 208 UV_RUNTIME_CHECK(uv_async_init, r); 209 uv_handle_set_data(&loop->pause_trigger, loop); 210 211 r = uv_async_init(&loop->loop, &loop->shutdown_trigger, shutdown_cb); 212 UV_RUNTIME_CHECK(uv_async_init, r); 213 uv_handle_set_data(&loop->shutdown_trigger, loop); 214 215 r = uv_async_init(&loop->loop, &loop->async_trigger, isc__async_cb); 216 UV_RUNTIME_CHECK(uv_async_init, r); 217 uv_handle_set_data(&loop->async_trigger, loop); 218 219 r = uv_idle_init(&loop->loop, &loop->run_trigger); 220 UV_RUNTIME_CHECK(uv_idle_init, r); 221 uv_handle_set_data(&loop->run_trigger, loop); 222 223 r = uv_async_init(&loop->loop, &loop->destroy_trigger, destroy_cb); 224 UV_RUNTIME_CHECK(uv_async_init, r); 225 uv_handle_set_data(&loop->destroy_trigger, loop); 226 227 r = uv_prepare_init(&loop->loop, &loop->quiescent); 228 UV_RUNTIME_CHECK(uv_prepare_init, r); 229 uv_handle_set_data(&loop->quiescent, loop); 230 231 char name[16]; 232 snprintf(name, sizeof(name), "%s-%08" PRIx32, kind, tid); 233 isc_mem_create(&loop->mctx); 234 isc_mem_setname(loop->mctx, name); 235 236 isc_refcount_init(&loop->references, 1); 237 238 loop->magic = LOOP_MAGIC; 239 } 240 241 static void 242 quiescent_cb(uv_prepare_t *handle) { 243 UNUSED(handle); 244 245 #if defined(RCU_QSBR) 246 /* safe memory reclamation */ 247 rcu_quiescent_state(); 248 249 /* mark the thread offline when polling */ 250 rcu_thread_offline(); 251 #else 252 INSIST(!rcu_read_ongoing()); 253 #endif 254 } 255 256 static void 257 helper_close(isc_loop_t *loop) { 258 int r = uv_loop_close(&loop->loop); 259 UV_RUNTIME_CHECK(uv_loop_close, r); 260 261 INSIST(cds_wfcq_empty(&loop->async_jobs.head, &loop->async_jobs.tail)); 262 263 isc_mem_detach(&loop->mctx); 264 } 265 266 static void 267 loop_close(isc_loop_t *loop) { 268 int r = uv_loop_close(&loop->loop); 269 UV_RUNTIME_CHECK(uv_loop_close, r); 270 271 INSIST(cds_wfcq_empty(&loop->async_jobs.head, &loop->async_jobs.tail)); 272 INSIST(ISC_LIST_EMPTY(loop->run_jobs)); 273 274 loop->magic = 0; 275 276 isc_mem_detach(&loop->mctx); 277 } 278 279 static void * 280 helper_thread(void *arg) { 281 isc_loop_t *helper = (isc_loop_t *)arg; 282 283 int r = uv_prepare_start(&helper->quiescent, quiescent_cb); 284 UV_RUNTIME_CHECK(uv_prepare_start, r); 285 286 isc_barrier_wait(&helper->loopmgr->starting); 287 288 r = uv_run(&helper->loop, UV_RUN_DEFAULT); 289 UV_RUNTIME_CHECK(uv_run, r); 290 291 /* Invalidate the helper early */ 292 helper->magic = 0; 293 294 isc_barrier_wait(&helper->loopmgr->stopping); 295 296 return NULL; 297 } 298 299 static void * 300 loop_thread(void *arg) { 301 isc_loop_t *loop = (isc_loop_t *)arg; 302 isc_loopmgr_t *loopmgr = loop->loopmgr; 303 isc_loop_t *helper = &loopmgr->helpers[loop->tid]; 304 char name[32]; 305 /* Initialize the thread_local variables*/ 306 307 REQUIRE(isc__loop_local == NULL || isc__loop_local == loop); 308 isc__loop_local = loop; 309 310 isc__tid_init(loop->tid); 311 312 /* Start the helper thread */ 313 isc_thread_create(helper_thread, helper, &helper->thread); 314 snprintf(name, sizeof(name), "isc-helper-%04" PRIu32, loop->tid); 315 isc_thread_setname(helper->thread, name); 316 317 int r = uv_prepare_start(&loop->quiescent, quiescent_cb); 318 UV_RUNTIME_CHECK(uv_prepare_start, r); 319 320 isc_barrier_wait(&loopmgr->starting); 321 322 enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking( 323 &loop->async_jobs.head, &loop->async_jobs.tail, 324 &loop->setup_jobs.head, &loop->setup_jobs.tail); 325 INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK); 326 327 r = uv_async_send(&loop->async_trigger); 328 UV_RUNTIME_CHECK(uv_async_send, r); 329 330 r = uv_run(&loop->loop, UV_RUN_DEFAULT); 331 UV_RUNTIME_CHECK(uv_run, r); 332 333 isc__loop_local = NULL; 334 335 /* Invalidate the loop early */ 336 loop->magic = 0; 337 338 /* Shutdown the helper thread */ 339 r = uv_async_send(&helper->shutdown_trigger); 340 UV_RUNTIME_CHECK(uv_async_send, r); 341 342 isc_barrier_wait(&loopmgr->stopping); 343 344 return NULL; 345 } 346 347 /** 348 * Public 349 */ 350 351 static void 352 threadpool_initialize(uint32_t workers) { 353 char buf[11]; 354 int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf, 355 &(size_t){ sizeof(buf) }); 356 if (r == UV_ENOENT) { 357 snprintf(buf, sizeof(buf), "%" PRIu32, workers); 358 uv_os_setenv("UV_THREADPOOL_SIZE", buf); 359 } 360 } 361 362 static void 363 loop_destroy(isc_loop_t *loop) { 364 int r = uv_async_send(&loop->destroy_trigger); 365 UV_RUNTIME_CHECK(uv_async_send, r); 366 } 367 368 #if ISC_LOOP_TRACE 369 ISC_REFCOUNT_TRACE_IMPL(isc_loop, loop_destroy) 370 #else 371 ISC_REFCOUNT_IMPL(isc_loop, loop_destroy); 372 #endif 373 374 void 375 isc_loopmgr_create(isc_mem_t *mctx, uint32_t nloops, isc_loopmgr_t **loopmgrp) { 376 isc_loopmgr_t *loopmgr = NULL; 377 378 REQUIRE(loopmgrp != NULL && *loopmgrp == NULL); 379 REQUIRE(nloops > 0); 380 381 threadpool_initialize(nloops); 382 isc__tid_initcount(nloops); 383 384 loopmgr = isc_mem_get(mctx, sizeof(*loopmgr)); 385 *loopmgr = (isc_loopmgr_t){ 386 .nloops = nloops, 387 }; 388 389 isc_mem_attach(mctx, &loopmgr->mctx); 390 391 /* We need to double the number for loops and helpers */ 392 isc_barrier_init(&loopmgr->pausing, loopmgr->nloops * 2); 393 isc_barrier_init(&loopmgr->resuming, loopmgr->nloops * 2); 394 isc_barrier_init(&loopmgr->starting, loopmgr->nloops * 2); 395 isc_barrier_init(&loopmgr->stopping, loopmgr->nloops * 2); 396 397 loopmgr->loops = isc_mem_cget(loopmgr->mctx, loopmgr->nloops, 398 sizeof(loopmgr->loops[0])); 399 for (size_t i = 0; i < loopmgr->nloops; i++) { 400 isc_loop_t *loop = &loopmgr->loops[i]; 401 loop_init(loop, loopmgr, i, "loop"); 402 } 403 404 loopmgr->helpers = isc_mem_cget(loopmgr->mctx, loopmgr->nloops, 405 sizeof(loopmgr->helpers[0])); 406 for (size_t i = 0; i < loopmgr->nloops; i++) { 407 isc_loop_t *loop = &loopmgr->helpers[i]; 408 loop_init(loop, loopmgr, i, "helper"); 409 } 410 411 loopmgr->sigint = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr, 412 SIGINT); 413 loopmgr->sigterm = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr, 414 SIGTERM); 415 416 isc_signal_start(loopmgr->sigint); 417 isc_signal_start(loopmgr->sigterm); 418 419 loopmgr->magic = LOOPMGR_MAGIC; 420 421 *loopmgrp = loopmgr; 422 } 423 424 isc_job_t * 425 isc_loop_setup(isc_loop_t *loop, isc_job_cb cb, void *cbarg) { 426 REQUIRE(VALID_LOOP(loop)); 427 REQUIRE(cb != NULL); 428 429 isc_loopmgr_t *loopmgr = loop->loopmgr; 430 isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job)); 431 *job = (isc_job_t){ 432 .cb = cb, 433 .cbarg = cbarg, 434 }; 435 436 cds_wfcq_node_init(&job->wfcq_node); 437 438 REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) || 439 atomic_load(&loopmgr->paused)); 440 441 cds_wfcq_enqueue(&loop->setup_jobs.head, &loop->setup_jobs.tail, 442 &job->wfcq_node); 443 444 return job; 445 } 446 447 isc_job_t * 448 isc_loop_teardown(isc_loop_t *loop, isc_job_cb cb, void *cbarg) { 449 REQUIRE(VALID_LOOP(loop)); 450 451 isc_loopmgr_t *loopmgr = loop->loopmgr; 452 isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job)); 453 *job = (isc_job_t){ 454 .cb = cb, 455 .cbarg = cbarg, 456 }; 457 cds_wfcq_node_init(&job->wfcq_node); 458 459 REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) || 460 atomic_load(&loopmgr->paused)); 461 462 cds_wfcq_enqueue(&loop->teardown_jobs.head, &loop->teardown_jobs.tail, 463 &job->wfcq_node); 464 465 return job; 466 } 467 468 void 469 isc_loopmgr_setup(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) { 470 REQUIRE(VALID_LOOPMGR(loopmgr)); 471 REQUIRE(!atomic_load(&loopmgr->running) || 472 atomic_load(&loopmgr->paused)); 473 474 for (size_t i = 0; i < loopmgr->nloops; i++) { 475 isc_loop_t *loop = &loopmgr->loops[i]; 476 (void)isc_loop_setup(loop, cb, cbarg); 477 } 478 } 479 480 void 481 isc_loopmgr_teardown(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) { 482 REQUIRE(VALID_LOOPMGR(loopmgr)); 483 REQUIRE(!atomic_load(&loopmgr->running) || 484 atomic_load(&loopmgr->paused)); 485 486 for (size_t i = 0; i < loopmgr->nloops; i++) { 487 isc_loop_t *loop = &loopmgr->loops[i]; 488 (void)isc_loop_teardown(loop, cb, cbarg); 489 } 490 } 491 492 void 493 isc_loopmgr_run(isc_loopmgr_t *loopmgr) { 494 REQUIRE(VALID_LOOPMGR(loopmgr)); 495 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running, 496 &(bool){ false }, true)); 497 498 /* 499 * Always ignore SIGPIPE. 500 */ 501 ignore_signal(SIGPIPE, SIG_IGN); 502 503 /* 504 * The thread 0 is this one. 505 */ 506 for (size_t i = 1; i < loopmgr->nloops; i++) { 507 char name[32]; 508 isc_loop_t *loop = &loopmgr->loops[i]; 509 510 isc_thread_create(loop_thread, loop, &loop->thread); 511 512 snprintf(name, sizeof(name), "isc-loop-%04zu", i); 513 isc_thread_setname(loop->thread, name); 514 } 515 516 isc_thread_main(loop_thread, &loopmgr->loops[0]); 517 } 518 519 void 520 isc_loopmgr_pause(isc_loopmgr_t *loopmgr) { 521 REQUIRE(VALID_LOOPMGR(loopmgr)); 522 REQUIRE(isc_tid() != ISC_TID_UNKNOWN); 523 524 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 525 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 526 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 527 "loop exclusive mode: starting"); 528 } 529 530 for (size_t i = 0; i < loopmgr->nloops; i++) { 531 isc_loop_t *helper = &loopmgr->helpers[i]; 532 533 int r = uv_async_send(&helper->pause_trigger); 534 UV_RUNTIME_CHECK(uv_async_send, r); 535 } 536 537 for (size_t i = 0; i < loopmgr->nloops; i++) { 538 isc_loop_t *loop = &loopmgr->loops[i]; 539 540 /* Skip current loop */ 541 if (i == isc_tid()) { 542 continue; 543 } 544 545 int r = uv_async_send(&loop->pause_trigger); 546 UV_RUNTIME_CHECK(uv_async_send, r); 547 } 548 549 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused, 550 &(bool){ false }, true)); 551 pause_loop(CURRENT_LOOP(loopmgr)); 552 553 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 554 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 555 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 556 "loop exclusive mode: started"); 557 } 558 } 559 560 void 561 isc_loopmgr_resume(isc_loopmgr_t *loopmgr) { 562 REQUIRE(VALID_LOOPMGR(loopmgr)); 563 564 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 565 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 566 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 567 "loop exclusive mode: ending"); 568 } 569 570 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused, 571 &(bool){ true }, false)); 572 resume_loop(CURRENT_LOOP(loopmgr)); 573 574 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 575 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 576 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 577 "loop exclusive mode: ended"); 578 } 579 } 580 581 void 582 isc_loopmgr_destroy(isc_loopmgr_t **loopmgrp) { 583 isc_loopmgr_t *loopmgr = NULL; 584 585 REQUIRE(loopmgrp != NULL); 586 REQUIRE(VALID_LOOPMGR(*loopmgrp)); 587 588 loopmgr = *loopmgrp; 589 *loopmgrp = NULL; 590 591 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running, 592 &(bool){ true }, false)); 593 594 /* Wait for all helpers to finish */ 595 for (size_t i = 0; i < loopmgr->nloops; i++) { 596 isc_loop_t *helper = &loopmgr->helpers[i]; 597 isc_thread_join(helper->thread, NULL); 598 } 599 600 /* First wait for all loops to finish */ 601 for (size_t i = 1; i < loopmgr->nloops; i++) { 602 isc_loop_t *loop = &loopmgr->loops[i]; 603 isc_thread_join(loop->thread, NULL); 604 } 605 606 loopmgr->magic = 0; 607 608 for (size_t i = 0; i < loopmgr->nloops; i++) { 609 isc_loop_t *helper = &loopmgr->helpers[i]; 610 helper_close(helper); 611 } 612 isc_mem_cput(loopmgr->mctx, loopmgr->helpers, loopmgr->nloops, 613 sizeof(loopmgr->helpers[0])); 614 615 for (size_t i = 0; i < loopmgr->nloops; i++) { 616 isc_loop_t *loop = &loopmgr->loops[i]; 617 loop_close(loop); 618 } 619 isc_mem_cput(loopmgr->mctx, loopmgr->loops, loopmgr->nloops, 620 sizeof(loopmgr->loops[0])); 621 622 isc_barrier_destroy(&loopmgr->starting); 623 isc_barrier_destroy(&loopmgr->stopping); 624 isc_barrier_destroy(&loopmgr->resuming); 625 isc_barrier_destroy(&loopmgr->pausing); 626 627 isc_mem_putanddetach(&loopmgr->mctx, loopmgr, sizeof(*loopmgr)); 628 } 629 630 uint32_t 631 isc_loopmgr_nloops(isc_loopmgr_t *loopmgr) { 632 REQUIRE(VALID_LOOPMGR(loopmgr)); 633 634 return loopmgr->nloops; 635 } 636 637 isc_mem_t * 638 isc_loop_getmctx(isc_loop_t *loop) { 639 REQUIRE(VALID_LOOP(loop)); 640 641 return loop->mctx; 642 } 643 644 isc_loop_t * 645 isc_loop_main(isc_loopmgr_t *loopmgr) { 646 REQUIRE(VALID_LOOPMGR(loopmgr)); 647 648 return DEFAULT_LOOP(loopmgr); 649 } 650 651 isc_loop_t * 652 isc_loop_get(isc_loopmgr_t *loopmgr, uint32_t tid) { 653 REQUIRE(VALID_LOOPMGR(loopmgr)); 654 REQUIRE(tid < loopmgr->nloops); 655 656 return LOOP(loopmgr, tid); 657 } 658 659 void 660 isc_loopmgr_blocking(isc_loopmgr_t *loopmgr) { 661 REQUIRE(VALID_LOOPMGR(loopmgr)); 662 663 isc_signal_stop(loopmgr->sigterm); 664 isc_signal_stop(loopmgr->sigint); 665 } 666 667 void 668 isc_loopmgr_nonblocking(isc_loopmgr_t *loopmgr) { 669 REQUIRE(VALID_LOOPMGR(loopmgr)); 670 671 isc_signal_start(loopmgr->sigint); 672 isc_signal_start(loopmgr->sigterm); 673 } 674 675 isc_loopmgr_t * 676 isc_loop_getloopmgr(isc_loop_t *loop) { 677 REQUIRE(VALID_LOOP(loop)); 678 679 return loop->loopmgr; 680 } 681 682 isc_time_t 683 isc_loop_now(isc_loop_t *loop) { 684 REQUIRE(VALID_LOOP(loop)); 685 686 uint64_t msec = uv_now(&loop->loop); 687 isc_time_t t = { 688 .seconds = msec / MS_PER_SEC, 689 .nanoseconds = (msec % MS_PER_SEC) * NS_PER_MS, 690 }; 691 692 return t; 693 } 694 695 bool 696 isc_loop_shuttingdown(isc_loop_t *loop) { 697 REQUIRE(VALID_LOOP(loop)); 698 REQUIRE(loop->tid == isc_tid()); 699 700 return loop->shuttingdown; 701 } 702