]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Create thread instance data for the main thread too (when not running in single threa...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 18 Mar 2026 23:32:15 +0000 (17:32 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 19 Mar 2026 01:43:44 +0000 (19:43 -0600)
This is needed for triggers to be able to call xlats

src/bin/radiusd.c
src/lib/io/schedule.c
src/lib/io/schedule.h
src/lib/server/connection.c
src/tests/util/radius_schedule_test.c
src/tests/util/schedule_test.c

index 25749c3deca0842171e214e2e9726918330b534a..e1503f75c5114f80c31a1cc2a054eaf08c4e1bc3 100644 (file)
@@ -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.
index 54a4acdf43cf0dd58cdcd7d5183bacf4fc50336a..6454975623329fe96e91d259e46d4351f4274715 100644 (file)
@@ -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;
index 26bee18a23ab63f3ec40066130879951d5c9f0e0..aaae2c4019f8306f464491cd81b793693d870c2a 100644 (file)
@@ -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));
index e554fb26034f751b86a07ba50ad7f1cdbfb647ac..cf52e27917e46d30fb45484ab7476caf4381bed9 100644 (file)
@@ -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);
index ed57e3880c12fce3cd440e44f2749a9b69788c59..6f4540c00b23672d818fe9b1e174c1f55a5b3d52 100644 (file)
@@ -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);
index 5938360050b7e573879f330dad5689907c09339f..43fd7a71b857c793d4e8ece1f947a8dbc91acc51 100644 (file)
@@ -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);