1 /* $NetBSD: loop.c,v 1.2 2025/01/26 16:25:37 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 loop->shuttingdown = true; 146 147 isc_loop_detach(&loop); 148 } 149 150 static void 151 destroy_cb(uv_async_t *handle) { 152 isc_loop_t *loop = uv_handle_get_data(handle); 153 154 /* Again, the first close callback here is called last */ 155 uv_close(&loop->async_trigger, isc__async_close); 156 uv_close(&loop->run_trigger, isc__job_close); 157 uv_close(&loop->destroy_trigger, NULL); 158 uv_close(&loop->pause_trigger, NULL); 159 uv_close(&loop->quiescent, NULL); 160 161 uv_walk(&loop->loop, loop_walk_cb, (char *)"destroy_cb"); 162 } 163 164 static void 165 shutdown_cb(uv_async_t *handle) { 166 isc_loop_t *loop = uv_handle_get_data(handle); 167 isc_loopmgr_t *loopmgr = loop->loopmgr; 168 169 /* Make sure, we can't be called again */ 170 uv_close(&loop->shutdown_trigger, shutdown_trigger_close_cb); 171 172 if (DEFAULT_LOOP(loopmgr) == CURRENT_LOOP(loopmgr)) { 173 /* Stop the signal handlers */ 174 isc_signal_stop(loopmgr->sigterm); 175 isc_signal_stop(loopmgr->sigint); 176 177 /* Free the signal handlers */ 178 isc_signal_destroy(&loopmgr->sigterm); 179 isc_signal_destroy(&loopmgr->sigint); 180 } 181 182 enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking( 183 &loop->async_jobs.head, &loop->async_jobs.tail, 184 &loop->teardown_jobs.head, &loop->teardown_jobs.tail); 185 INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK); 186 int r = uv_async_send(&loop->async_trigger); 187 UV_RUNTIME_CHECK(uv_async_send, r); 188 } 189 190 static void 191 loop_init(isc_loop_t *loop, isc_loopmgr_t *loopmgr, uint32_t tid, 192 const char *kind) { 193 *loop = (isc_loop_t){ 194 .tid = tid, 195 .loopmgr = loopmgr, 196 .run_jobs = ISC_LIST_INITIALIZER, 197 }; 198 199 __cds_wfcq_init(&loop->async_jobs.head, &loop->async_jobs.tail); 200 __cds_wfcq_init(&loop->setup_jobs.head, &loop->setup_jobs.tail); 201 __cds_wfcq_init(&loop->teardown_jobs.head, &loop->teardown_jobs.tail); 202 203 int r = uv_loop_init(&loop->loop); 204 UV_RUNTIME_CHECK(uv_loop_init, r); 205 206 r = uv_async_init(&loop->loop, &loop->pause_trigger, pauseresume_cb); 207 UV_RUNTIME_CHECK(uv_async_init, r); 208 uv_handle_set_data(&loop->pause_trigger, loop); 209 210 r = uv_async_init(&loop->loop, &loop->shutdown_trigger, shutdown_cb); 211 UV_RUNTIME_CHECK(uv_async_init, r); 212 uv_handle_set_data(&loop->shutdown_trigger, loop); 213 214 r = uv_async_init(&loop->loop, &loop->async_trigger, isc__async_cb); 215 UV_RUNTIME_CHECK(uv_async_init, r); 216 uv_handle_set_data(&loop->async_trigger, loop); 217 218 r = uv_idle_init(&loop->loop, &loop->run_trigger); 219 UV_RUNTIME_CHECK(uv_idle_init, r); 220 uv_handle_set_data(&loop->run_trigger, loop); 221 222 r = uv_async_init(&loop->loop, &loop->destroy_trigger, destroy_cb); 223 UV_RUNTIME_CHECK(uv_async_init, r); 224 uv_handle_set_data(&loop->destroy_trigger, loop); 225 226 r = uv_prepare_init(&loop->loop, &loop->quiescent); 227 UV_RUNTIME_CHECK(uv_prepare_init, r); 228 uv_handle_set_data(&loop->quiescent, loop); 229 230 char name[16]; 231 snprintf(name, sizeof(name), "%s-%08" PRIx32, kind, tid); 232 isc_mem_create(&loop->mctx); 233 isc_mem_setname(loop->mctx, name); 234 235 isc_refcount_init(&loop->references, 1); 236 237 loop->magic = LOOP_MAGIC; 238 } 239 240 static void 241 quiescent_cb(uv_prepare_t *handle) { 242 UNUSED(handle); 243 244 #if defined(RCU_QSBR) 245 /* safe memory reclamation */ 246 rcu_quiescent_state(); 247 248 /* mark the thread offline when polling */ 249 rcu_thread_offline(); 250 #else 251 INSIST(!rcu_read_ongoing()); 252 #endif 253 } 254 255 static void 256 helper_close(isc_loop_t *loop) { 257 int r = uv_loop_close(&loop->loop); 258 UV_RUNTIME_CHECK(uv_loop_close, r); 259 260 INSIST(cds_wfcq_empty(&loop->async_jobs.head, &loop->async_jobs.tail)); 261 262 isc_mem_detach(&loop->mctx); 263 } 264 265 static void 266 loop_close(isc_loop_t *loop) { 267 int r = uv_loop_close(&loop->loop); 268 UV_RUNTIME_CHECK(uv_loop_close, r); 269 270 INSIST(cds_wfcq_empty(&loop->async_jobs.head, &loop->async_jobs.tail)); 271 INSIST(ISC_LIST_EMPTY(loop->run_jobs)); 272 273 loop->magic = 0; 274 275 isc_mem_detach(&loop->mctx); 276 } 277 278 static void * 279 helper_thread(void *arg) { 280 isc_loop_t *helper = (isc_loop_t *)arg; 281 282 int r = uv_prepare_start(&helper->quiescent, quiescent_cb); 283 UV_RUNTIME_CHECK(uv_prepare_start, r); 284 285 isc_barrier_wait(&helper->loopmgr->starting); 286 287 r = uv_run(&helper->loop, UV_RUN_DEFAULT); 288 UV_RUNTIME_CHECK(uv_run, r); 289 290 /* Invalidate the helper early */ 291 helper->magic = 0; 292 293 isc_barrier_wait(&helper->loopmgr->stopping); 294 295 return NULL; 296 } 297 298 static void * 299 loop_thread(void *arg) { 300 isc_loop_t *loop = (isc_loop_t *)arg; 301 isc_loopmgr_t *loopmgr = loop->loopmgr; 302 isc_loop_t *helper = &loopmgr->helpers[loop->tid]; 303 char name[32]; 304 /* Initialize the thread_local variables*/ 305 306 REQUIRE(isc__loop_local == NULL || isc__loop_local == loop); 307 isc__loop_local = loop; 308 309 isc__tid_init(loop->tid); 310 311 /* Start the helper thread */ 312 isc_thread_create(helper_thread, helper, &helper->thread); 313 snprintf(name, sizeof(name), "isc-helper-%04" PRIu32, loop->tid); 314 isc_thread_setname(helper->thread, name); 315 316 int r = uv_prepare_start(&loop->quiescent, quiescent_cb); 317 UV_RUNTIME_CHECK(uv_prepare_start, r); 318 319 isc_barrier_wait(&loopmgr->starting); 320 321 enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking( 322 &loop->async_jobs.head, &loop->async_jobs.tail, 323 &loop->setup_jobs.head, &loop->setup_jobs.tail); 324 INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK); 325 326 r = uv_async_send(&loop->async_trigger); 327 UV_RUNTIME_CHECK(uv_async_send, r); 328 329 r = uv_run(&loop->loop, UV_RUN_DEFAULT); 330 UV_RUNTIME_CHECK(uv_run, r); 331 332 isc__loop_local = NULL; 333 334 /* Invalidate the loop early */ 335 loop->magic = 0; 336 337 /* Shutdown the helper thread */ 338 r = uv_async_send(&helper->shutdown_trigger); 339 UV_RUNTIME_CHECK(uv_async_send, r); 340 341 isc_barrier_wait(&loopmgr->stopping); 342 343 return NULL; 344 } 345 346 /** 347 * Public 348 */ 349 350 static void 351 threadpool_initialize(uint32_t workers) { 352 char buf[11]; 353 int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf, 354 &(size_t){ sizeof(buf) }); 355 if (r == UV_ENOENT) { 356 snprintf(buf, sizeof(buf), "%" PRIu32, workers); 357 uv_os_setenv("UV_THREADPOOL_SIZE", buf); 358 } 359 } 360 361 static void 362 loop_destroy(isc_loop_t *loop) { 363 int r = uv_async_send(&loop->destroy_trigger); 364 UV_RUNTIME_CHECK(uv_async_send, r); 365 } 366 367 #if ISC_LOOP_TRACE 368 ISC_REFCOUNT_TRACE_IMPL(isc_loop, loop_destroy) 369 #else 370 ISC_REFCOUNT_IMPL(isc_loop, loop_destroy); 371 #endif 372 373 void 374 isc_loopmgr_create(isc_mem_t *mctx, uint32_t nloops, isc_loopmgr_t **loopmgrp) { 375 isc_loopmgr_t *loopmgr = NULL; 376 377 REQUIRE(loopmgrp != NULL && *loopmgrp == NULL); 378 REQUIRE(nloops > 0); 379 380 threadpool_initialize(nloops); 381 isc__tid_initcount(nloops); 382 383 loopmgr = isc_mem_get(mctx, sizeof(*loopmgr)); 384 *loopmgr = (isc_loopmgr_t){ 385 .nloops = nloops, 386 }; 387 388 isc_mem_attach(mctx, &loopmgr->mctx); 389 390 /* We need to double the number for loops and helpers */ 391 isc_barrier_init(&loopmgr->pausing, loopmgr->nloops * 2); 392 isc_barrier_init(&loopmgr->resuming, loopmgr->nloops * 2); 393 isc_barrier_init(&loopmgr->starting, loopmgr->nloops * 2); 394 isc_barrier_init(&loopmgr->stopping, loopmgr->nloops * 2); 395 396 loopmgr->loops = isc_mem_cget(loopmgr->mctx, loopmgr->nloops, 397 sizeof(loopmgr->loops[0])); 398 for (size_t i = 0; i < loopmgr->nloops; i++) { 399 isc_loop_t *loop = &loopmgr->loops[i]; 400 loop_init(loop, loopmgr, i, "loop"); 401 } 402 403 loopmgr->helpers = isc_mem_cget(loopmgr->mctx, loopmgr->nloops, 404 sizeof(loopmgr->helpers[0])); 405 for (size_t i = 0; i < loopmgr->nloops; i++) { 406 isc_loop_t *loop = &loopmgr->helpers[i]; 407 loop_init(loop, loopmgr, i, "helper"); 408 } 409 410 loopmgr->sigint = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr, 411 SIGINT); 412 loopmgr->sigterm = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr, 413 SIGTERM); 414 415 isc_signal_start(loopmgr->sigint); 416 isc_signal_start(loopmgr->sigterm); 417 418 loopmgr->magic = LOOPMGR_MAGIC; 419 420 *loopmgrp = loopmgr; 421 } 422 423 isc_job_t * 424 isc_loop_setup(isc_loop_t *loop, isc_job_cb cb, void *cbarg) { 425 REQUIRE(VALID_LOOP(loop)); 426 REQUIRE(cb != NULL); 427 428 isc_loopmgr_t *loopmgr = loop->loopmgr; 429 isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job)); 430 *job = (isc_job_t){ 431 .cb = cb, 432 .cbarg = cbarg, 433 }; 434 435 cds_wfcq_node_init(&job->wfcq_node); 436 437 REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) || 438 atomic_load(&loopmgr->paused)); 439 440 cds_wfcq_enqueue(&loop->setup_jobs.head, &loop->setup_jobs.tail, 441 &job->wfcq_node); 442 443 return job; 444 } 445 446 isc_job_t * 447 isc_loop_teardown(isc_loop_t *loop, isc_job_cb cb, void *cbarg) { 448 REQUIRE(VALID_LOOP(loop)); 449 450 isc_loopmgr_t *loopmgr = loop->loopmgr; 451 isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job)); 452 *job = (isc_job_t){ 453 .cb = cb, 454 .cbarg = cbarg, 455 }; 456 cds_wfcq_node_init(&job->wfcq_node); 457 458 REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) || 459 atomic_load(&loopmgr->paused)); 460 461 cds_wfcq_enqueue(&loop->teardown_jobs.head, &loop->teardown_jobs.tail, 462 &job->wfcq_node); 463 464 return job; 465 } 466 467 void 468 isc_loopmgr_setup(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) { 469 REQUIRE(VALID_LOOPMGR(loopmgr)); 470 REQUIRE(!atomic_load(&loopmgr->running) || 471 atomic_load(&loopmgr->paused)); 472 473 for (size_t i = 0; i < loopmgr->nloops; i++) { 474 isc_loop_t *loop = &loopmgr->loops[i]; 475 (void)isc_loop_setup(loop, cb, cbarg); 476 } 477 } 478 479 void 480 isc_loopmgr_teardown(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) { 481 REQUIRE(VALID_LOOPMGR(loopmgr)); 482 REQUIRE(!atomic_load(&loopmgr->running) || 483 atomic_load(&loopmgr->paused)); 484 485 for (size_t i = 0; i < loopmgr->nloops; i++) { 486 isc_loop_t *loop = &loopmgr->loops[i]; 487 (void)isc_loop_teardown(loop, cb, cbarg); 488 } 489 } 490 491 void 492 isc_loopmgr_run(isc_loopmgr_t *loopmgr) { 493 REQUIRE(VALID_LOOPMGR(loopmgr)); 494 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running, 495 &(bool){ false }, true)); 496 497 /* 498 * Always ignore SIGPIPE. 499 */ 500 ignore_signal(SIGPIPE, SIG_IGN); 501 502 /* 503 * The thread 0 is this one. 504 */ 505 for (size_t i = 1; i < loopmgr->nloops; i++) { 506 char name[32]; 507 isc_loop_t *loop = &loopmgr->loops[i]; 508 509 isc_thread_create(loop_thread, loop, &loop->thread); 510 511 snprintf(name, sizeof(name), "isc-loop-%04zu", i); 512 isc_thread_setname(loop->thread, name); 513 } 514 515 isc_thread_main(loop_thread, &loopmgr->loops[0]); 516 } 517 518 void 519 isc_loopmgr_pause(isc_loopmgr_t *loopmgr) { 520 REQUIRE(VALID_LOOPMGR(loopmgr)); 521 REQUIRE(isc_tid() != ISC_TID_UNKNOWN); 522 523 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 524 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 525 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 526 "loop exclusive mode: starting"); 527 } 528 529 for (size_t i = 0; i < loopmgr->nloops; i++) { 530 isc_loop_t *helper = &loopmgr->helpers[i]; 531 532 int r = uv_async_send(&helper->pause_trigger); 533 UV_RUNTIME_CHECK(uv_async_send, r); 534 } 535 536 for (size_t i = 0; i < loopmgr->nloops; i++) { 537 isc_loop_t *loop = &loopmgr->loops[i]; 538 539 /* Skip current loop */ 540 if (i == isc_tid()) { 541 continue; 542 } 543 544 int r = uv_async_send(&loop->pause_trigger); 545 UV_RUNTIME_CHECK(uv_async_send, r); 546 } 547 548 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused, 549 &(bool){ false }, true)); 550 pause_loop(CURRENT_LOOP(loopmgr)); 551 552 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 553 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 554 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 555 "loop exclusive mode: started"); 556 } 557 } 558 559 void 560 isc_loopmgr_resume(isc_loopmgr_t *loopmgr) { 561 REQUIRE(VALID_LOOPMGR(loopmgr)); 562 563 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 564 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 565 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 566 "loop exclusive mode: ending"); 567 } 568 569 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused, 570 &(bool){ true }, false)); 571 resume_loop(CURRENT_LOOP(loopmgr)); 572 573 if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) { 574 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 575 ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1), 576 "loop exclusive mode: ended"); 577 } 578 } 579 580 void 581 isc_loopmgr_destroy(isc_loopmgr_t **loopmgrp) { 582 isc_loopmgr_t *loopmgr = NULL; 583 584 REQUIRE(loopmgrp != NULL); 585 REQUIRE(VALID_LOOPMGR(*loopmgrp)); 586 587 loopmgr = *loopmgrp; 588 *loopmgrp = NULL; 589 590 RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running, 591 &(bool){ true }, false)); 592 593 /* Wait for all helpers to finish */ 594 for (size_t i = 0; i < loopmgr->nloops; i++) { 595 isc_loop_t *helper = &loopmgr->helpers[i]; 596 isc_thread_join(helper->thread, NULL); 597 } 598 599 /* First wait for all loops to finish */ 600 for (size_t i = 1; i < loopmgr->nloops; i++) { 601 isc_loop_t *loop = &loopmgr->loops[i]; 602 isc_thread_join(loop->thread, NULL); 603 } 604 605 loopmgr->magic = 0; 606 607 for (size_t i = 0; i < loopmgr->nloops; i++) { 608 isc_loop_t *helper = &loopmgr->helpers[i]; 609 helper_close(helper); 610 } 611 isc_mem_cput(loopmgr->mctx, loopmgr->helpers, loopmgr->nloops, 612 sizeof(loopmgr->helpers[0])); 613 614 for (size_t i = 0; i < loopmgr->nloops; i++) { 615 isc_loop_t *loop = &loopmgr->loops[i]; 616 loop_close(loop); 617 } 618 isc_mem_cput(loopmgr->mctx, loopmgr->loops, loopmgr->nloops, 619 sizeof(loopmgr->loops[0])); 620 621 isc_barrier_destroy(&loopmgr->starting); 622 isc_barrier_destroy(&loopmgr->stopping); 623 isc_barrier_destroy(&loopmgr->resuming); 624 isc_barrier_destroy(&loopmgr->pausing); 625 626 isc_mem_putanddetach(&loopmgr->mctx, loopmgr, sizeof(*loopmgr)); 627 } 628 629 uint32_t 630 isc_loopmgr_nloops(isc_loopmgr_t *loopmgr) { 631 REQUIRE(VALID_LOOPMGR(loopmgr)); 632 633 return loopmgr->nloops; 634 } 635 636 isc_mem_t * 637 isc_loop_getmctx(isc_loop_t *loop) { 638 REQUIRE(VALID_LOOP(loop)); 639 640 return loop->mctx; 641 } 642 643 isc_loop_t * 644 isc_loop_main(isc_loopmgr_t *loopmgr) { 645 REQUIRE(VALID_LOOPMGR(loopmgr)); 646 647 return DEFAULT_LOOP(loopmgr); 648 } 649 650 isc_loop_t * 651 isc_loop_get(isc_loopmgr_t *loopmgr, uint32_t tid) { 652 REQUIRE(VALID_LOOPMGR(loopmgr)); 653 REQUIRE(tid < loopmgr->nloops); 654 655 return LOOP(loopmgr, tid); 656 } 657 658 void 659 isc_loopmgr_blocking(isc_loopmgr_t *loopmgr) { 660 REQUIRE(VALID_LOOPMGR(loopmgr)); 661 662 isc_signal_stop(loopmgr->sigterm); 663 isc_signal_stop(loopmgr->sigint); 664 } 665 666 void 667 isc_loopmgr_nonblocking(isc_loopmgr_t *loopmgr) { 668 REQUIRE(VALID_LOOPMGR(loopmgr)); 669 670 isc_signal_start(loopmgr->sigint); 671 isc_signal_start(loopmgr->sigterm); 672 } 673 674 isc_loopmgr_t * 675 isc_loop_getloopmgr(isc_loop_t *loop) { 676 REQUIRE(VALID_LOOP(loop)); 677 678 return loop->loopmgr; 679 } 680 681 isc_time_t 682 isc_loop_now(isc_loop_t *loop) { 683 REQUIRE(VALID_LOOP(loop)); 684 685 uint64_t msec = uv_now(&loop->loop); 686 isc_time_t t = { 687 .seconds = msec / MS_PER_SEC, 688 .nanoseconds = (msec % MS_PER_SEC) * NS_PER_MS, 689 }; 690 691 return t; 692 } 693 694 bool 695 isc_loop_shuttingdown(isc_loop_t *loop) { 696 REQUIRE(VALID_LOOP(loop)); 697 REQUIRE(loop->tid == isc_tid()); 698 699 return loop->shuttingdown; 700 } 701