From 18fec256b72f18763a9817888609c89ab19c9686 Mon Sep 17 00:00:00 2001 From: Yorgos Thessalonikefs Date: Fri, 6 Feb 2026 14:15:32 +0100 Subject: [PATCH] - Support pthread_setname_np, and variants, to set the name on spawned threads for easier debugging/monitoring. --- configure.ac | 67 +++++++++++++++++++++++++++++++++++++++++++++++ daemon/daemon.c | 7 +++++ daemon/remote.c | 4 +++ dnstap/dtstream.c | 4 +++ util/locks.h | 27 +++++++++++++++++++ 5 files changed, 109 insertions(+) diff --git a/configure.ac b/configure.ac index 41eedc2fd..ddf31b787 100644 --- a/configure.ac +++ b/configure.ac @@ -731,6 +731,73 @@ int main(void) {return 0;} ]) fi +if test x_$ub_have_pthreads != x_no; then + # Long checks to support pthread_setname_np(). + # Some OSes have the extra non-portable functions in a specific + # header file. + AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT]) + # MacOS only has 1 argument, the name. + AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.]) + ],[ + AC_MSG_RESULT(no) + ]) + # NetBSD has 3 arguments to allow for formatting of the name. + AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(0, "", NULL); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.]) + ],[ + AC_MSG_RESULT(no) + ]) + # Most OSes have the common 2 arguments, thread and name. + AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(0, ""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.]) + ],[ + AC_MSG_RESULT(no) + ]) + # FreeBSD/OpenBSD use a slightly different function name. + AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_set_name_np(0, ""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.]) + ],[ + AC_MSG_RESULT(no) + ]) +fi + # check solaris thread library AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ]) ub_have_sol_threads=no diff --git a/daemon/daemon.c b/daemon/daemon.c index 72cd0dc82..bc358df0c 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -662,7 +662,14 @@ thread_start(void* arg) { struct worker* worker = (struct worker*)arg; int port_num = 0; + log_assert(worker->thr_id); set_log_thread_id(worker, worker->daemon->cfg); + { + char name[16]; /* seems to be the safest size between + different OSes */ + snprintf(name, sizeof(name), "unbound/%u", worker->thread_num); + ub_thread_setname(worker->thr_id, name); + } ub_thread_blocksigs(); #ifdef THREADS_DISABLED /* close pipe ends used by main */ diff --git a/daemon/remote.c b/daemon/remote.c index 00e7dd21d..69ffff4ba 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -6635,6 +6635,8 @@ static void* fast_reload_thread_main(void* arg) struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg; struct timeval time_start, time_read, time_construct, time_reload, time_end; + const char name[16] = "unbound/freload"; /* seems to be the safest size + between different OSes */ #if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) fast_reload_thread->thread_tid = gettid(); @@ -6644,6 +6646,8 @@ static void* fast_reload_thread_main(void* arg) #endif log_thread_set(&fast_reload_thread->threadnum); + ub_thread_setname(fast_reload_thread->tid, name); + verbose(VERB_ALGO, "start fast reload thread"); if(fast_reload_thread->fr_verb >= 1) { fr_init_time(&time_start, &time_read, &time_construct, diff --git a/dnstap/dtstream.c b/dnstap/dtstream.c index 30db6f219..09bdfd662 100644 --- a/dnstap/dtstream.c +++ b/dnstap/dtstream.c @@ -2133,6 +2133,8 @@ static void* dnstap_io(void* arg) struct dt_io_thread* dtio = (struct dt_io_thread*)arg; time_t secs = 0; struct timeval now; + const char name[16] = "unbound/dnstap"; /* seems to be the safest size + between different OSes */ #if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) dtio->thread_tid = gettid(); @@ -2142,6 +2144,8 @@ static void* dnstap_io(void* arg) #endif log_thread_set(&dtio->threadnum); + ub_thread_setname(dtio->tid, name); + /* setup */ verbose(VERB_ALGO, "start dnstap io thread"); dtio_setup_base(dtio, &secs, &now); diff --git a/util/locks.h b/util/locks.h index eb698cb75..9b1b10b37 100644 --- a/util/locks.h +++ b/util/locks.h @@ -178,6 +178,30 @@ typedef pthread_key_t ub_thread_key_type; #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) #define ub_thread_key_get(key) pthread_getspecific(key) +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#if defined(HAVE_PTHREAD_SET_NAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_set_name_np(thread, name);\ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP1) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(name); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP3) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name, NULL); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name); \ + } while(0) +#else + #define ub_thread_setname(thread, name) /* nop */ +#endif /* HAVE_PTHREAD_SET_NAME_NP */ + + #else /* we do not HAVE_PTHREAD */ #ifdef HAVE_SOLARIS_THREADS @@ -215,6 +239,7 @@ typedef thread_key_t ub_thread_key_type; #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ @@ -253,6 +278,7 @@ typedef DWORD ub_thread_key_type; void ub_thread_key_create(ub_thread_key_type* key, void* f); void ub_thread_key_set(ub_thread_key_type key, void* v); void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ @@ -294,6 +320,7 @@ typedef void* ub_thread_key_type; #define ub_thread_key_create(key, f) (*(key)) = NULL #define ub_thread_key_set(key, v) (key) = (v) #define ub_thread_key_get(key) (key) +#define ub_thread_setname(thread, name) /* nop */ #endif /* HAVE_WINDOWS_THREADS */ #endif /* HAVE_SOLARIS_THREADS */