mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 05:28:00 +00:00
Move registration and deregistration of the main thread from `isc_loopmgr_run()` into `isc__initialize()` / `isc__shutdown()`: liburcu-qsbr fails an assertion if we try to use it from an unregistered thread, and we need to be able to use it when the event loops are not running. Use `rcu_assign_pointer()` and `rcu_dereference()` in qp-trie transactions so that they properly mark threads as online. The RCU-protected pointer is no longer declared atomic because liburcu does not (yet) use standard C atomics. Fix the definition of `isc_qsbr_rcu_dereference()` to return the referenced value, and to call the right function inside liburcu. Change the thread sanitizer suppressions to match any variant of `rcu_*_barrier()`
609 lines
14 KiB
C
609 lines
14 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <isc/async.h>
|
|
#include <isc/atomic.h>
|
|
#include <isc/barrier.h>
|
|
#include <isc/condition.h>
|
|
#include <isc/job.h>
|
|
#include <isc/list.h>
|
|
#include <isc/log.h>
|
|
#include <isc/loop.h>
|
|
#include <isc/magic.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/mutex.h>
|
|
#include <isc/refcount.h>
|
|
#include <isc/result.h>
|
|
#include <isc/signal.h>
|
|
#include <isc/strerr.h>
|
|
#include <isc/thread.h>
|
|
#include <isc/tid.h>
|
|
#include <isc/urcu.h>
|
|
#include <isc/util.h>
|
|
#include <isc/uv.h>
|
|
#include <isc/work.h>
|
|
|
|
#include "async_p.h"
|
|
#include "job_p.h"
|
|
#include "loop_p.h"
|
|
|
|
/**
|
|
* Private
|
|
*/
|
|
|
|
static void
|
|
ignore_signal(int sig, void (*handler)(int)) {
|
|
struct sigaction sa = { .sa_handler = handler };
|
|
|
|
if (sigfillset(&sa.sa_mask) != 0 || sigaction(sig, &sa, NULL) < 0) {
|
|
FATAL_SYSERROR(errno, "ignore_signal(%d)", sig);
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_shutdown(isc_loopmgr_t *loopmgr) {
|
|
if (!atomic_compare_exchange_strong(&loopmgr->shuttingdown,
|
|
&(bool){ false }, true))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
int r;
|
|
|
|
r = uv_async_send(&loop->shutdown_trigger);
|
|
UV_RUNTIME_CHECK(uv_async_send, r);
|
|
}
|
|
}
|
|
|
|
static void
|
|
isc__loopmgr_signal(void *arg, int signum) {
|
|
isc_loopmgr_t *loopmgr = (isc_loopmgr_t *)arg;
|
|
|
|
switch (signum) {
|
|
case SIGINT:
|
|
case SIGTERM:
|
|
isc_loopmgr_shutdown(loopmgr);
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
static void
|
|
pause_loop(isc_loop_t *loop) {
|
|
isc_loopmgr_t *loopmgr = loop->loopmgr;
|
|
|
|
rcu_thread_offline();
|
|
|
|
loop->paused = true;
|
|
(void)isc_barrier_wait(&loopmgr->pausing);
|
|
}
|
|
|
|
static void
|
|
resume_loop(isc_loop_t *loop) {
|
|
isc_loopmgr_t *loopmgr = loop->loopmgr;
|
|
|
|
(void)isc_barrier_wait(&loopmgr->resuming);
|
|
loop->paused = false;
|
|
|
|
rcu_thread_online();
|
|
}
|
|
|
|
static void
|
|
pauseresume_cb(uv_async_t *handle) {
|
|
isc_loop_t *loop = uv_handle_get_data(handle);
|
|
|
|
pause_loop(loop);
|
|
resume_loop(loop);
|
|
}
|
|
|
|
#define XX(uc, lc) \
|
|
case UV_##uc: \
|
|
fprintf(stderr, "%s, %s: dangling %p: %p.type = %s\n", \
|
|
__func__, (char *)arg, handle->loop, handle, #lc); \
|
|
break;
|
|
|
|
static void
|
|
loop_walk_cb(uv_handle_t *handle, void *arg) {
|
|
if (uv_is_closing(handle)) {
|
|
return;
|
|
}
|
|
|
|
switch (handle->type) {
|
|
UV_HANDLE_TYPE_MAP(XX)
|
|
default:
|
|
fprintf(stderr, "%s, %s: dangling %p: %p.type = %s\n", __func__,
|
|
(char *)arg, &handle->loop, handle, "unknown");
|
|
}
|
|
}
|
|
|
|
static void
|
|
shutdown_trigger_close_cb(uv_handle_t *handle) {
|
|
isc_loop_t *loop = uv_handle_get_data(handle);
|
|
|
|
isc_loop_detach(&loop);
|
|
}
|
|
|
|
static void
|
|
destroy_cb(uv_async_t *handle) {
|
|
isc_loop_t *loop = uv_handle_get_data(handle);
|
|
|
|
/* Again, the first close callback here is called last */
|
|
uv_close(&loop->async_trigger, isc__async_close);
|
|
uv_close(&loop->run_trigger, isc__job_close);
|
|
uv_close(&loop->destroy_trigger, NULL);
|
|
uv_close(&loop->pause_trigger, NULL);
|
|
uv_close(&loop->quiescent, NULL);
|
|
|
|
uv_walk(&loop->loop, loop_walk_cb, (char *)"destroy_cb");
|
|
}
|
|
|
|
static void
|
|
shutdown_cb(uv_async_t *handle) {
|
|
isc_loop_t *loop = uv_handle_get_data(handle);
|
|
isc_loopmgr_t *loopmgr = loop->loopmgr;
|
|
|
|
/* Make sure, we can't be called again */
|
|
uv_close(&loop->shutdown_trigger, shutdown_trigger_close_cb);
|
|
|
|
if (DEFAULT_LOOP(loopmgr) == CURRENT_LOOP(loopmgr)) {
|
|
/* Stop the signal handlers */
|
|
isc_signal_stop(loopmgr->sigterm);
|
|
isc_signal_stop(loopmgr->sigint);
|
|
|
|
/* Free the signal handlers */
|
|
isc_signal_destroy(&loopmgr->sigterm);
|
|
isc_signal_destroy(&loopmgr->sigint);
|
|
}
|
|
|
|
enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking(
|
|
&loop->async_jobs.head, &loop->async_jobs.tail,
|
|
&loop->teardown_jobs.head, &loop->teardown_jobs.tail);
|
|
INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK);
|
|
int r = uv_async_send(&loop->async_trigger);
|
|
UV_RUNTIME_CHECK(uv_async_send, r);
|
|
}
|
|
|
|
static void
|
|
loop_init(isc_loop_t *loop, isc_loopmgr_t *loopmgr, uint32_t tid) {
|
|
*loop = (isc_loop_t){
|
|
.tid = tid,
|
|
.loopmgr = loopmgr,
|
|
.run_jobs = ISC_LIST_INITIALIZER,
|
|
};
|
|
|
|
__cds_wfcq_init(&loop->async_jobs.head, &loop->async_jobs.tail);
|
|
__cds_wfcq_init(&loop->setup_jobs.head, &loop->setup_jobs.tail);
|
|
__cds_wfcq_init(&loop->teardown_jobs.head, &loop->teardown_jobs.tail);
|
|
|
|
int r = uv_loop_init(&loop->loop);
|
|
UV_RUNTIME_CHECK(uv_loop_init, r);
|
|
|
|
r = uv_async_init(&loop->loop, &loop->pause_trigger, pauseresume_cb);
|
|
UV_RUNTIME_CHECK(uv_async_init, r);
|
|
uv_handle_set_data(&loop->pause_trigger, loop);
|
|
|
|
r = uv_async_init(&loop->loop, &loop->shutdown_trigger, shutdown_cb);
|
|
UV_RUNTIME_CHECK(uv_async_init, r);
|
|
uv_handle_set_data(&loop->shutdown_trigger, loop);
|
|
|
|
r = uv_async_init(&loop->loop, &loop->async_trigger, isc__async_cb);
|
|
UV_RUNTIME_CHECK(uv_async_init, r);
|
|
uv_handle_set_data(&loop->async_trigger, loop);
|
|
|
|
r = uv_idle_init(&loop->loop, &loop->run_trigger);
|
|
UV_RUNTIME_CHECK(uv_idle_init, r);
|
|
uv_handle_set_data(&loop->run_trigger, loop);
|
|
|
|
r = uv_async_init(&loop->loop, &loop->destroy_trigger, destroy_cb);
|
|
UV_RUNTIME_CHECK(uv_async_init, r);
|
|
uv_handle_set_data(&loop->destroy_trigger, loop);
|
|
|
|
r = uv_prepare_init(&loop->loop, &loop->quiescent);
|
|
UV_RUNTIME_CHECK(uv_prepare_init, r);
|
|
uv_handle_set_data(&loop->quiescent, loop);
|
|
|
|
char name[16];
|
|
snprintf(name, sizeof(name), "loop-%08" PRIx32, tid);
|
|
isc_mem_create(&loop->mctx);
|
|
isc_mem_setname(loop->mctx, name);
|
|
|
|
isc_refcount_init(&loop->references, 1);
|
|
|
|
loop->magic = LOOP_MAGIC;
|
|
}
|
|
|
|
static void
|
|
quiescent_cb(uv_prepare_t *handle) {
|
|
UNUSED(handle);
|
|
|
|
#if defined(RCU_QSBR)
|
|
/* safe memory reclamation */
|
|
rcu_quiescent_state();
|
|
|
|
/* mark the thread offline when polling */
|
|
rcu_thread_offline();
|
|
#else
|
|
INSIST(!rcu_read_ongoing());
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
loop_close(isc_loop_t *loop) {
|
|
int r = uv_loop_close(&loop->loop);
|
|
UV_RUNTIME_CHECK(uv_loop_close, r);
|
|
|
|
INSIST(cds_wfcq_empty(&loop->async_jobs.head, &loop->async_jobs.tail));
|
|
INSIST(ISC_LIST_EMPTY(loop->run_jobs));
|
|
|
|
loop->magic = 0;
|
|
|
|
isc_mem_detach(&loop->mctx);
|
|
}
|
|
|
|
static void *
|
|
loop_thread(void *arg) {
|
|
isc_loop_t *loop = (isc_loop_t *)arg;
|
|
|
|
/* Initialize the thread_local variable */
|
|
|
|
isc__tid_init(loop->tid);
|
|
|
|
int r = uv_prepare_start(&loop->quiescent, quiescent_cb);
|
|
UV_RUNTIME_CHECK(uv_prepare_start, r);
|
|
|
|
isc_barrier_wait(&loop->loopmgr->starting);
|
|
|
|
enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking(
|
|
&loop->async_jobs.head, &loop->async_jobs.tail,
|
|
&loop->setup_jobs.head, &loop->setup_jobs.tail);
|
|
INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK);
|
|
|
|
r = uv_async_send(&loop->async_trigger);
|
|
UV_RUNTIME_CHECK(uv_async_send, r);
|
|
|
|
r = uv_run(&loop->loop, UV_RUN_DEFAULT);
|
|
UV_RUNTIME_CHECK(uv_run, r);
|
|
|
|
isc_barrier_wait(&loop->loopmgr->stopping);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/**
|
|
* Public
|
|
*/
|
|
|
|
static void
|
|
threadpool_initialize(uint32_t workers) {
|
|
char buf[11];
|
|
int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf,
|
|
&(size_t){ sizeof(buf) });
|
|
if (r == UV_ENOENT) {
|
|
snprintf(buf, sizeof(buf), "%" PRIu32, workers);
|
|
uv_os_setenv("UV_THREADPOOL_SIZE", buf);
|
|
}
|
|
}
|
|
|
|
static void
|
|
loop_destroy(isc_loop_t *loop) {
|
|
int r = uv_async_send(&loop->destroy_trigger);
|
|
UV_RUNTIME_CHECK(uv_async_send, r);
|
|
}
|
|
|
|
#if ISC_LOOP_TRACE
|
|
ISC_REFCOUNT_TRACE_IMPL(isc_loop, loop_destroy)
|
|
#else
|
|
ISC_REFCOUNT_IMPL(isc_loop, loop_destroy);
|
|
#endif
|
|
|
|
void
|
|
isc_loopmgr_create(isc_mem_t *mctx, uint32_t nloops, isc_loopmgr_t **loopmgrp) {
|
|
isc_loopmgr_t *loopmgr = NULL;
|
|
|
|
REQUIRE(loopmgrp != NULL && *loopmgrp == NULL);
|
|
REQUIRE(nloops > 0);
|
|
|
|
threadpool_initialize(nloops);
|
|
isc__tid_initcount(nloops);
|
|
|
|
loopmgr = isc_mem_get(mctx, sizeof(*loopmgr));
|
|
*loopmgr = (isc_loopmgr_t){
|
|
.nloops = nloops,
|
|
};
|
|
|
|
isc_mem_attach(mctx, &loopmgr->mctx);
|
|
|
|
isc_barrier_init(&loopmgr->pausing, loopmgr->nloops);
|
|
isc_barrier_init(&loopmgr->resuming, loopmgr->nloops);
|
|
isc_barrier_init(&loopmgr->starting, loopmgr->nloops);
|
|
isc_barrier_init(&loopmgr->stopping, loopmgr->nloops);
|
|
|
|
loopmgr->loops = isc_mem_get(
|
|
loopmgr->mctx, loopmgr->nloops * sizeof(loopmgr->loops[0]));
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
loop_init(loop, loopmgr, i);
|
|
}
|
|
|
|
loopmgr->sigint = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr,
|
|
SIGINT);
|
|
loopmgr->sigterm = isc_signal_new(loopmgr, isc__loopmgr_signal, loopmgr,
|
|
SIGTERM);
|
|
|
|
isc_signal_start(loopmgr->sigint);
|
|
isc_signal_start(loopmgr->sigterm);
|
|
|
|
loopmgr->magic = LOOPMGR_MAGIC;
|
|
|
|
*loopmgrp = loopmgr;
|
|
}
|
|
|
|
isc_job_t *
|
|
isc_loop_setup(isc_loop_t *loop, isc_job_cb cb, void *cbarg) {
|
|
REQUIRE(VALID_LOOP(loop));
|
|
REQUIRE(cb != NULL);
|
|
|
|
isc_loopmgr_t *loopmgr = loop->loopmgr;
|
|
isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job));
|
|
*job = (isc_job_t){
|
|
.cb = cb,
|
|
.cbarg = cbarg,
|
|
};
|
|
|
|
cds_wfcq_node_init(&job->wfcq_node);
|
|
|
|
REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) ||
|
|
atomic_load(&loopmgr->paused));
|
|
|
|
cds_wfcq_enqueue(&loop->setup_jobs.head, &loop->setup_jobs.tail,
|
|
&job->wfcq_node);
|
|
|
|
return (job);
|
|
}
|
|
|
|
isc_job_t *
|
|
isc_loop_teardown(isc_loop_t *loop, isc_job_cb cb, void *cbarg) {
|
|
REQUIRE(VALID_LOOP(loop));
|
|
|
|
isc_loopmgr_t *loopmgr = loop->loopmgr;
|
|
isc_job_t *job = isc_mem_get(loop->mctx, sizeof(*job));
|
|
*job = (isc_job_t){
|
|
.cb = cb,
|
|
.cbarg = cbarg,
|
|
};
|
|
cds_wfcq_node_init(&job->wfcq_node);
|
|
|
|
REQUIRE(loop->tid == isc_tid() || !atomic_load(&loopmgr->running) ||
|
|
atomic_load(&loopmgr->paused));
|
|
|
|
cds_wfcq_enqueue(&loop->teardown_jobs.head, &loop->teardown_jobs.tail,
|
|
&job->wfcq_node);
|
|
|
|
return (job);
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_setup(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
REQUIRE(!atomic_load(&loopmgr->running) ||
|
|
atomic_load(&loopmgr->paused));
|
|
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
(void)isc_loop_setup(loop, cb, cbarg);
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_teardown(isc_loopmgr_t *loopmgr, isc_job_cb cb, void *cbarg) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
REQUIRE(!atomic_load(&loopmgr->running) ||
|
|
atomic_load(&loopmgr->paused));
|
|
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
(void)isc_loop_teardown(loop, cb, cbarg);
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_run(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running,
|
|
&(bool){ false }, true));
|
|
|
|
/*
|
|
* Always ignore SIGPIPE.
|
|
*/
|
|
ignore_signal(SIGPIPE, SIG_IGN);
|
|
|
|
bool free_call_rcu_data = !create_all_cpu_call_rcu_data(0);
|
|
|
|
/*
|
|
* The thread 0 is this one.
|
|
*/
|
|
for (size_t i = 1; i < loopmgr->nloops; i++) {
|
|
char name[32];
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
|
|
isc_thread_create(loop_thread, loop, &loop->thread);
|
|
|
|
snprintf(name, sizeof(name), "isc-loop-%04zu", i);
|
|
isc_thread_setname(loop->thread, name);
|
|
}
|
|
|
|
isc_thread_main(loop_thread, &loopmgr->loops[0]);
|
|
|
|
rcu_barrier();
|
|
|
|
if (free_call_rcu_data) {
|
|
free_all_cpu_call_rcu_data();
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_pause(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) {
|
|
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
|
ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1),
|
|
"loop exclusive mode: starting");
|
|
}
|
|
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
|
|
/* Skip current loop */
|
|
if (i == isc_tid()) {
|
|
continue;
|
|
}
|
|
|
|
int r = uv_async_send(&loop->pause_trigger);
|
|
UV_RUNTIME_CHECK(uv_async_send, r);
|
|
}
|
|
|
|
RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused,
|
|
&(bool){ false }, true));
|
|
pause_loop(CURRENT_LOOP(loopmgr));
|
|
|
|
if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) {
|
|
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
|
ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1),
|
|
"loop exclusive mode: started");
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_resume(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) {
|
|
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
|
ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1),
|
|
"loop exclusive mode: ending");
|
|
}
|
|
|
|
RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->paused,
|
|
&(bool){ true }, false));
|
|
resume_loop(CURRENT_LOOP(loopmgr));
|
|
|
|
if (isc_log_wouldlog(isc_lctx, ISC_LOG_DEBUG(1))) {
|
|
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
|
ISC_LOGMODULE_OTHER, ISC_LOG_DEBUG(1),
|
|
"loop exclusive mode: ended");
|
|
}
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_destroy(isc_loopmgr_t **loopmgrp) {
|
|
isc_loopmgr_t *loopmgr = NULL;
|
|
|
|
REQUIRE(loopmgrp != NULL);
|
|
REQUIRE(VALID_LOOPMGR(*loopmgrp));
|
|
|
|
loopmgr = *loopmgrp;
|
|
*loopmgrp = NULL;
|
|
|
|
RUNTIME_CHECK(atomic_compare_exchange_strong(&loopmgr->running,
|
|
&(bool){ true }, false));
|
|
|
|
/* First wait for all loops to finish */
|
|
for (size_t i = 1; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
isc_thread_join(loop->thread, NULL);
|
|
}
|
|
|
|
loopmgr->magic = 0;
|
|
|
|
for (size_t i = 0; i < loopmgr->nloops; i++) {
|
|
isc_loop_t *loop = &loopmgr->loops[i];
|
|
loop_close(loop);
|
|
}
|
|
isc_mem_put(loopmgr->mctx, loopmgr->loops,
|
|
loopmgr->nloops * sizeof(loopmgr->loops[0]));
|
|
|
|
isc_barrier_destroy(&loopmgr->starting);
|
|
isc_barrier_destroy(&loopmgr->stopping);
|
|
isc_barrier_destroy(&loopmgr->resuming);
|
|
isc_barrier_destroy(&loopmgr->pausing);
|
|
|
|
isc_mem_putanddetach(&loopmgr->mctx, loopmgr, sizeof(*loopmgr));
|
|
}
|
|
|
|
uint32_t
|
|
isc_loopmgr_nloops(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
return (loopmgr->nloops);
|
|
}
|
|
|
|
isc_mem_t *
|
|
isc_loop_getmctx(isc_loop_t *loop) {
|
|
REQUIRE(VALID_LOOP(loop));
|
|
|
|
return (loop->mctx);
|
|
}
|
|
|
|
isc_loop_t *
|
|
isc_loop_main(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
return (DEFAULT_LOOP(loopmgr));
|
|
}
|
|
|
|
isc_loop_t *
|
|
isc_loop_current(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
return (CURRENT_LOOP(loopmgr));
|
|
}
|
|
|
|
isc_loop_t *
|
|
isc_loop_get(isc_loopmgr_t *loopmgr, uint32_t tid) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
REQUIRE(tid < loopmgr->nloops);
|
|
|
|
return (LOOP(loopmgr, tid));
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_blocking(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
isc_signal_stop(loopmgr->sigterm);
|
|
isc_signal_stop(loopmgr->sigint);
|
|
}
|
|
|
|
void
|
|
isc_loopmgr_nonblocking(isc_loopmgr_t *loopmgr) {
|
|
REQUIRE(VALID_LOOPMGR(loopmgr));
|
|
|
|
isc_signal_start(loopmgr->sigint);
|
|
isc_signal_start(loopmgr->sigterm);
|
|
}
|
|
|
|
isc_loopmgr_t *
|
|
isc_loop_getloopmgr(isc_loop_t *loop) {
|
|
REQUIRE(VALID_LOOP(loop));
|
|
|
|
return (loop->loopmgr);
|
|
}
|