loop.c revision 1.1.1.1 1 /* $NetBSD: loop.c,v 1.1.1.1 2025/01/26 16:12:31 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