Coverage Report

Created: 2026-08-13 07:07

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