mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
Move per-thread RCU setup into isc_thread
All the per-loop `libuv` setup remains in `isc_loop`, but the per-thread RCU setup is moved to `isc_thread` alongside the other per-thread setup. This avoids repeating the per-thread setup for `call_rcu()` helpers, and explains a little better why some parts of the per-thread setup is missing for `call_rcu()` helpers. This also removes the per-loop `call_rcu()` helpers as we refactored the isc__random_initialize() in the previous commit.
This commit is contained in:
parent
65021dbf52
commit
7d1ceaf35d
@ -35,6 +35,13 @@ ISC_LANG_BEGINDECLS
|
|||||||
typedef pthread_t isc_thread_t;
|
typedef pthread_t isc_thread_t;
|
||||||
typedef void *(*isc_threadfunc_t)(void *);
|
typedef void *(*isc_threadfunc_t)(void *);
|
||||||
|
|
||||||
|
/*%
|
||||||
|
* like isc_thread_create(), but run the function on the current
|
||||||
|
* thread which must be the main thread.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
isc_thread_main(isc_threadfunc_t, void *);
|
||||||
|
|
||||||
void
|
void
|
||||||
isc_thread_create(isc_threadfunc_t, void *, isc_thread_t *);
|
isc_thread_create(isc_threadfunc_t, void *, isc_thread_t *);
|
||||||
|
|
||||||
|
@ -247,9 +247,19 @@
|
|||||||
#endif /* if __has_feature(thread_sanitizer) */
|
#endif /* if __has_feature(thread_sanitizer) */
|
||||||
|
|
||||||
#if __SANITIZE_THREAD__
|
#if __SANITIZE_THREAD__
|
||||||
|
/*
|
||||||
|
* We should rather be including <sanitizer/tsan_interface.h>, but GCC 10
|
||||||
|
* header is broken, so we just make the declarations by hand.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__tsan_acquire(void *addr);
|
||||||
|
void
|
||||||
|
__tsan_release(void *addr);
|
||||||
#define ISC_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
|
#define ISC_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
|
||||||
#else /* if __SANITIZE_THREAD__ */
|
#else /* if __SANITIZE_THREAD__ */
|
||||||
#define ISC_NO_SANITIZE_THREAD
|
#define ISC_NO_SANITIZE_THREAD
|
||||||
|
#define __tsan_acquire(addr)
|
||||||
|
#define __tsan_release(addr)
|
||||||
#endif /* if __SANITIZE_THREAD__ */
|
#endif /* if __SANITIZE_THREAD__ */
|
||||||
|
|
||||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6)
|
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6)
|
||||||
|
@ -103,6 +103,7 @@ resume_loop(isc_loop_t *loop) {
|
|||||||
|
|
||||||
(void)isc_barrier_wait(&loopmgr->resuming);
|
(void)isc_barrier_wait(&loopmgr->resuming);
|
||||||
loop->paused = false;
|
loop->paused = false;
|
||||||
|
|
||||||
rcu_thread_online();
|
rcu_thread_online();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,54 +269,17 @@ static void
|
|||||||
quiescent_cb(uv_prepare_t *handle) {
|
quiescent_cb(uv_prepare_t *handle) {
|
||||||
isc__qsbr_quiescent_cb(handle);
|
isc__qsbr_quiescent_cb(handle);
|
||||||
|
|
||||||
#ifndef RCU_QSBR
|
#if defined(RCU_QSBR)
|
||||||
INSIST(!rcu_read_ongoing());
|
|
||||||
#else
|
|
||||||
/* safe memory reclamation */
|
/* safe memory reclamation */
|
||||||
rcu_quiescent_state();
|
rcu_quiescent_state();
|
||||||
|
|
||||||
/* mark the thread offline when polling */
|
/* mark the thread offline when polling */
|
||||||
rcu_thread_offline();
|
rcu_thread_offline();
|
||||||
|
#else
|
||||||
|
INSIST(!rcu_read_ongoing());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
loop_call_rcu_init(struct rcu_head *rcu_head __attribute__((__unused__))) {
|
|
||||||
/* Work around the jemalloc bug, see trampoline.c for details */
|
|
||||||
void *ptr = malloc(8);
|
|
||||||
free(ptr);
|
|
||||||
|
|
||||||
/* Initialize the random generator in the call_rcu thread */
|
|
||||||
isc__random_initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
loop_run(isc_loop_t *loop) {
|
|
||||||
int r = uv_prepare_start(&loop->quiescent, quiescent_cb);
|
|
||||||
UV_RUNTIME_CHECK(uv_prepare_start, r);
|
|
||||||
|
|
||||||
isc_barrier_wait(&loop->loopmgr->starting);
|
|
||||||
|
|
||||||
isc_async_run(loop, setup_jobs_cb, loop);
|
|
||||||
|
|
||||||
rcu_register_thread();
|
|
||||||
|
|
||||||
struct call_rcu_data *crdp = create_call_rcu_data(0, -1);
|
|
||||||
set_thread_call_rcu_data(crdp);
|
|
||||||
|
|
||||||
call_rcu(&loop->rcu_head, loop_call_rcu_init);
|
|
||||||
|
|
||||||
r = uv_run(&loop->loop, UV_RUN_DEFAULT);
|
|
||||||
UV_RUNTIME_CHECK(uv_run, r);
|
|
||||||
|
|
||||||
rcu_unregister_thread();
|
|
||||||
|
|
||||||
set_thread_call_rcu_data(NULL);
|
|
||||||
call_rcu_data_free(crdp);
|
|
||||||
|
|
||||||
isc_barrier_wait(&loop->loopmgr->stopping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
loop_close(isc_loop_t *loop) {
|
loop_close(isc_loop_t *loop) {
|
||||||
int r = uv_loop_close(&loop->loop);
|
int r = uv_loop_close(&loop->loop);
|
||||||
@ -337,7 +301,17 @@ loop_thread(void *arg) {
|
|||||||
|
|
||||||
isc__tid_init(loop->tid);
|
isc__tid_init(loop->tid);
|
||||||
|
|
||||||
loop_run(loop);
|
int r = uv_prepare_start(&loop->quiescent, quiescent_cb);
|
||||||
|
UV_RUNTIME_CHECK(uv_prepare_start, r);
|
||||||
|
|
||||||
|
isc_barrier_wait(&loop->loopmgr->starting);
|
||||||
|
|
||||||
|
isc_async_run(loop, setup_jobs_cb, loop);
|
||||||
|
|
||||||
|
r = uv_run(&loop->loop, UV_RUN_DEFAULT);
|
||||||
|
UV_RUNTIME_CHECK(uv_run, r);
|
||||||
|
|
||||||
|
isc_barrier_wait(&loop->loopmgr->stopping);
|
||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@ -511,7 +485,7 @@ isc_loopmgr_run(isc_loopmgr_t *loopmgr) {
|
|||||||
isc_thread_setname(loop->thread, name);
|
isc_thread_setname(loop->thread, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_thread(&loopmgr->loops[0]);
|
isc_thread_main(loop_thread, &loopmgr->loops[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include <isc/stack.h>
|
#include <isc/stack.h>
|
||||||
#include <isc/thread.h>
|
#include <isc/thread.h>
|
||||||
#include <isc/types.h>
|
#include <isc/types.h>
|
||||||
#include <isc/urcu.h>
|
|
||||||
#include <isc/uv.h>
|
#include <isc/uv.h>
|
||||||
#include <isc/work.h>
|
#include <isc/work.h>
|
||||||
|
|
||||||
@ -80,8 +79,6 @@ struct isc_loop {
|
|||||||
uv_async_t wakeup_trigger;
|
uv_async_t wakeup_trigger;
|
||||||
uv_prepare_t quiescent;
|
uv_prepare_t quiescent;
|
||||||
isc_qsbr_phase_t qsbr_phase;
|
isc_qsbr_phase_t qsbr_phase;
|
||||||
|
|
||||||
struct rcu_head rcu_head;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,9 +30,12 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <isc/atomic.h>
|
||||||
#include <isc/iterated_hash.h>
|
#include <isc/iterated_hash.h>
|
||||||
#include <isc/strerr.h>
|
#include <isc/strerr.h>
|
||||||
#include <isc/thread.h>
|
#include <isc/thread.h>
|
||||||
|
#include <isc/tid.h>
|
||||||
|
#include <isc/urcu.h>
|
||||||
#include <isc/util.h>
|
#include <isc/util.h>
|
||||||
|
|
||||||
#ifndef THREAD_MINSTACKSIZE
|
#ifndef THREAD_MINSTACKSIZE
|
||||||
@ -46,18 +49,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct thread_wrap {
|
struct thread_wrap {
|
||||||
|
struct rcu_head rcu_head;
|
||||||
isc_threadfunc_t func;
|
isc_threadfunc_t func;
|
||||||
void *arg;
|
void *arg;
|
||||||
void (*free)(void *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct thread_wrap *
|
static struct thread_wrap *
|
||||||
thread_wrap(isc_threadfunc_t func, void *arg) {
|
thread_wrap(isc_threadfunc_t func, void *arg) {
|
||||||
struct thread_wrap *wrap = malloc(sizeof(*wrap));
|
struct thread_wrap *wrap = malloc(sizeof(*wrap));
|
||||||
|
|
||||||
RUNTIME_CHECK(wrap != NULL);
|
|
||||||
*wrap = (struct thread_wrap){
|
*wrap = (struct thread_wrap){
|
||||||
.free = free, /* from stdlib */
|
|
||||||
.func = func,
|
.func = func,
|
||||||
.arg = arg,
|
.arg = arg,
|
||||||
};
|
};
|
||||||
@ -66,30 +66,56 @@ thread_wrap(isc_threadfunc_t func, void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
thread_run(void *arg) {
|
thread_body(struct thread_wrap *wrap) {
|
||||||
struct thread_wrap *wrap = arg;
|
isc_threadfunc_t func = wrap->func;
|
||||||
isc_threadfunc_t wrap_func = wrap->func;
|
void *arg = wrap->arg;
|
||||||
void *wrap_arg = wrap->arg;
|
void *ret = NULL;
|
||||||
void *result = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Every thread starts with a malloc() call to prevent memory bloat
|
* Every thread starts with a malloc() call to prevent memory bloat
|
||||||
* caused by a jemalloc quirk. To stop an optimizing compiler from
|
* caused by a jemalloc quirk. We use CMM_ACCESS_ONCE() To stop an
|
||||||
* stripping out free(malloc(1)), we call free via a function pointer.
|
* optimizing compiler from stripping out free(malloc(1)).
|
||||||
*/
|
*/
|
||||||
wrap->free(malloc(1));
|
void *jemalloc_enforce_init = NULL;
|
||||||
wrap->free(wrap);
|
CMM_ACCESS_ONCE(jemalloc_enforce_init) = malloc(1);
|
||||||
|
free(jemalloc_enforce_init);
|
||||||
|
|
||||||
/* Get a thread-local digest context. */
|
/* Reassure Thread Sanitizer that it is safe to free the wrapper */
|
||||||
|
__tsan_acquire(wrap);
|
||||||
|
free(wrap);
|
||||||
|
|
||||||
|
rcu_register_thread();
|
||||||
|
|
||||||
|
ret = func(arg);
|
||||||
|
|
||||||
|
rcu_unregister_thread();
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
thread_run(void *wrap) {
|
||||||
|
/*
|
||||||
|
* Get a thread-local digest context only in new threads.
|
||||||
|
* The main thread is handled by isc__initialize().
|
||||||
|
*/
|
||||||
isc__iterated_hash_initialize();
|
isc__iterated_hash_initialize();
|
||||||
|
|
||||||
/* Run the main function */
|
void *ret = thread_body(wrap);
|
||||||
result = wrap_func(wrap_arg);
|
|
||||||
|
|
||||||
/* Cleanup */
|
|
||||||
isc__iterated_hash_shutdown();
|
isc__iterated_hash_shutdown();
|
||||||
|
|
||||||
return (result);
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
isc_thread_main(isc_threadfunc_t func, void *arg) {
|
||||||
|
/*
|
||||||
|
* Either this thread has not yet been started, so it can become the
|
||||||
|
* main thread, or it has already been annointed as the chosen zero
|
||||||
|
*/
|
||||||
|
REQUIRE(isc_tid() == ISC_TID_UNKNOWN || isc_tid() == 0);
|
||||||
|
thread_body(thread_wrap(func, arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user