From: Arran Cudbard-Bell Date: Wed, 18 Mar 2026 23:32:15 +0000 (-0600) Subject: Create thread instance data for the main thread too (when not running in single threa... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e0318ed5dd56ab6ccc00ce226ff4ebb4e16ca1c7;p=thirdparty%2Ffreeradius-server.git Create thread instance data for the main thread too (when not running in single threaded mode) This is needed for triggers to be able to call xlats --- diff --git a/src/bin/radiusd.c b/src/bin/radiusd.c index 25749c3deca..e1503f75c51 100644 --- a/src/bin/radiusd.c +++ b/src/bin/radiusd.c @@ -846,7 +846,6 @@ do { \ * Start the network / worker threads. */ { - fr_event_list_t *el = NULL; fr_schedule_config_t *schedule; MEM(schedule = talloc_zero(global_ctx, fr_schedule_config_t)); @@ -858,20 +857,12 @@ do { \ schedule->worker = config->worker; schedule->cs = cf_section_find(config->root_cs, "thread", CF_IDENT_ANY); - /* - * Single server mode: use the global event list. - * Otherwise, each network thread will create - * its own event list. - */ - if (!config->spawn_workers) { - el = main_loop_event_list(); - } - /* * Fix spurious messages */ fr_strerror_clear(); - sc = fr_schedule_create(NULL, el, &default_log, fr_debug_lvl, + sc = fr_schedule_create(NULL, !config->spawn_workers, main_loop_event_list(), + &default_log, fr_debug_lvl, thread_instantiate, thread_detach, schedule); if (!sc) { PERROR("Failed starting the scheduler"); @@ -1052,7 +1043,9 @@ do { \ * to exit gracefully. fr_schedule_destroy only returns once all * threads have been joined. */ - (void) fr_schedule_destroy(&sc); + if (unlikely(fr_schedule_destroy(&sc) < 0)) { + EXIT_WITH_PERROR; + } /* * We're exiting, so we can delete the PID file. diff --git a/src/lib/io/schedule.c b/src/lib/io/schedule.c index 54a4acdf43c..64549756233 100644 --- a/src/lib/io/schedule.c +++ b/src/lib/io/schedule.c @@ -78,6 +78,7 @@ struct fr_schedule_s { CONF_SECTION *cs; //!< thread pool configuration section fr_event_list_t *el; //!< event list for single-threaded mode. + bool single_threaded; //!< true if running in single-threaded mode. fr_log_t *log; //!< log destination fr_log_lvl_t lvl; //!< log level @@ -250,6 +251,7 @@ fail: /** Create a scheduler and spawn the child threads. * * @param[in] ctx talloc context. + * @param[in] single_threaded no workers are spawned, everything runs in a common event loop. * @param[in] el event list, only for single-threaded mode. * @param[in] logger destination for all logging messages. * @param[in] lvl log level. @@ -261,7 +263,9 @@ fail: * - NULL on error * - fr_schedule_t new scheduler */ -fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, +fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, + bool single_threaded, + fr_event_list_t *el, fr_log_t *logger, fr_log_lvl_t lvl, fr_schedule_thread_instantiate_t worker_thread_instantiate, fr_schedule_thread_detach_t worker_thread_detach, @@ -295,6 +299,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, } sc->el = el; + sc->single_threaded = single_threaded; sc->log = logger; sc->lvl = lvl; sc->cs = sc->config->cs; @@ -306,7 +311,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, /* * If we're single-threaded, create network / worker, and insert them into the event loop. */ - if (el) { + if (single_threaded) { sc->single_network = fr_network_create(sc, el, "Network", sc->log, sc->lvl, &sc->config->network); if (!sc->single_network) { PERROR("Failed creating network"); @@ -536,6 +541,18 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, if (sc) INFO("Scheduler created successfully with %u networks and %u workers", sc->config->max_networks, (unsigned int)fr_dlist_num_elements(&sc->workers)); + /* + * Instantiate thread-local data for the main thread too. + * In single-threaded mode this is done above. In + * multi-worker mode the main thread also needs module + * thread data so that triggers can use module xlats. + */ + if (sc->worker_thread_instantiate && + unlikely((sc->worker_thread_instantiate(NULL, el, NULL) < 0))) { + PERROR("Main thread instantiation failed"); + goto mt_fail; + } + return sc; } @@ -562,10 +579,12 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free) sc->running = false; + + /* * Single threaded mode: kill the only network / worker we have. */ - if (sc->el) { + if (sc->single_threaded) { /* * Destroy the network side first. It tells the * workers to close. @@ -575,7 +594,16 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free) } fr_worker_destroy(sc->single_worker); fr_coords_destroy(); + goto done; + } else { + /* + * Detach thread-local data for the main thread. + * Worker threads handle their own detach, but + * the main thread was instantiated explicitly + * by fr_schedule_create. + */ + if (sc->worker_thread_detach) sc->worker_thread_detach(NULL); } /* @@ -651,6 +679,7 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free) fr_sem_free(sc->coord_sem); fr_sem_free(sc->network_sem); fr_sem_free(sc->worker_sem); + done: /* * Now that all of the workers are done, we can return to @@ -676,7 +705,7 @@ fr_network_t *fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li) (void) talloc_get_type_abort(sc, fr_schedule_t); - if (sc->el) { + if (sc->single_threaded) { nr = sc->single_network; } else { fr_schedule_network_t *sn; @@ -708,7 +737,7 @@ fr_network_t *fr_schedule_directory_add(fr_schedule_t *sc, fr_listen_t *li) (void) talloc_get_type_abort(sc, fr_schedule_t); - if (sc->el) { + if (sc->single_threaded) { nr = sc->single_network; } else { fr_schedule_network_t *sn; diff --git a/src/lib/io/schedule.h b/src/lib/io/schedule.h index 26bee18a23a..aaae2c4019f 100644 --- a/src/lib/io/schedule.h +++ b/src/lib/io/schedule.h @@ -75,7 +75,8 @@ typedef struct { int fr_schedule_worker_id(void); -fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_log_t *log, fr_log_lvl_t lvl, +fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, bool single_threaded, fr_event_list_t *el, + fr_log_t *log, fr_log_lvl_t lvl, fr_schedule_thread_instantiate_t worker_thread_instantiate, fr_schedule_thread_detach_t worker_thread_detach, fr_schedule_config_t *config) CC_HINT(nonnull(3)); diff --git a/src/lib/server/connection.c b/src/lib/server/connection.c index e554fb26034..cf52e27917e 100644 --- a/src/lib/server/connection.c +++ b/src/lib/server/connection.c @@ -1538,7 +1538,7 @@ connection_t *connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, connection_t *conn; uint64_t id; - fr_assert(el); + fr_assert_msg(el, "No event list provided"); MEM(conn = talloc(ctx, connection_t)); talloc_set_destructor(conn, _connection_free); diff --git a/src/tests/util/radius_schedule_test.c b/src/tests/util/radius_schedule_test.c index ed57e3880c1..6f4540c00b2 100644 --- a/src/tests/util/radius_schedule_test.c +++ b/src/tests/util/radius_schedule_test.c @@ -276,7 +276,7 @@ int main(int argc, char *argv[]) app_io_inst->ipaddr = my_ipaddr; app_io_inst->port = my_port; - sched = fr_schedule_create(autofree, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL); + sched = fr_schedule_create(autofree, false, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL); if (!sched) { fprintf(stderr, "schedule_test: Failed to create scheduler\n"); fr_exit_now(EXIT_FAILURE); diff --git a/src/tests/util/schedule_test.c b/src/tests/util/schedule_test.c index 5938360050b..43fd7a71b85 100644 --- a/src/tests/util/schedule_test.c +++ b/src/tests/util/schedule_test.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) argv += (optind - 1); #endif - sched = fr_schedule_create(autofree, NULL, &default_log, L_DBG_LVL_MAX, num_networks, num_workers, NULL, NULL); + sched = fr_schedule_create(autofree, false, NULL, &default_log, L_DBG_LVL_MAX, num_networks, num_workers, NULL, NULL); if (!sched) { fprintf(stderr, "schedule_test: Failed to create scheduler\n"); fr_exit_now(EXIT_FAILURE);