]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move thread information to a common data structure
authorAlan T. DeKok <aland@freeradius.org>
Sun, 15 Mar 2026 17:54:58 +0000 (13:54 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 15 Mar 2026 18:30:38 +0000 (14:30 -0400)
src/lib/io/coord.c
src/lib/io/schedule.c
src/lib/io/thread.c
src/lib/io/thread.h

index 3998f82b50968335669add88c817d1b4a8d86c29..447eba1763cce5cc445b8d369f44651b2c2b06a5 100644 (file)
@@ -92,14 +92,12 @@ struct fr_coord_reg_s {
 /** Scheduler specific information for coordinator threads
  */
 typedef struct {
-       TALLOC_CTX                      *ctx;                   //!< Our allocation ctx
-       fr_event_list_t                 *el;                    //!< Event list for this coordinator.
-       pthread_t                       pthread_id;             //!< the thread of this coordinator
+       fr_thread_t                     thread;                 //!< common thread information - must be first!
+
        uint32_t                        max_workers;            //!< Maximum number of workers which will connect to this coordinator.
        fr_coord_reg_t                  *coord_reg;             //!< Coordinator registration details.
        fr_coord_t                      *coord;                 //!< The coordinator data structure.
        fr_sem_t                        *sem;                   //!< For inter-thread signaling.
-       fr_dlist_t                      entry;                  //!< Entry in list of running coordinator threads.
 } fr_schedule_coord_t;
 
 /** Control plane message used for workers attaching / detaching to coordinators
@@ -179,7 +177,7 @@ void fr_coord_deregister(fr_coord_reg_t *coord_reg)
 
        fr_dlist_foreach(coord_threads, fr_schedule_coord_t, sc) {
                if (sc->coord_reg == coord_reg) {
-                       if ((ret = pthread_join(sc->pthread_id, NULL)) != 0) {
+                       if ((ret = pthread_join(sc->thread.pthread_id, NULL)) != 0) {
                                ERROR("Failed joining coordinator %s: %s", coord_reg->name, fr_syserror(ret));
                        } else {
                                DEBUG2("Coordinator %s joined (cleaned up)", coord_reg->name);
@@ -444,19 +442,17 @@ static void fr_coordinate(fr_coord_t *coord)
  */
 static void *fr_coordinate_thread(void *arg)
 {
-       TALLOC_CTX              *ctx;
        fr_schedule_coord_t     *sc = talloc_get_type_abort(arg, fr_schedule_coord_t);
        fr_coord_reg_t          *coord_reg = sc->coord_reg;
        char                    coordinate_name[64];
 
        snprintf(coordinate_name, sizeof(coordinate_name), "Coordinate %s", coord_reg->name);
 
-       if (fr_thread_setup(&ctx, &sc->el, coordinate_name) < 0) goto fail;
-       sc->ctx = ctx;
+       if (fr_thread_setup(&sc->thread, coordinate_name) < 0) goto fail;
 
        INFO("%s - Starting", coordinate_name);
 
-       sc->coord = fr_coord_create(ctx, sc->el, coord_reg, false, sc->max_workers);
+       sc->coord = fr_coord_create(sc->thread.ctx, sc->thread.el, coord_reg, false, sc->max_workers);
        if (!sc->coord) {
                PERROR("%s - Failed creating coordinator thread", coordinate_name);
                goto fail;
@@ -465,7 +461,7 @@ static void *fr_coordinate_thread(void *arg)
        /*
         *      Create all the thread specific data for the coordinator thread
         */
-       if (fr_thread_instantiate(ctx, sc->el) < 0) goto fail;
+       if (fr_thread_instantiate(sc->thread.ctx, sc->thread.el) < 0) goto fail;
 
        sem_post(sc->sem);
 
@@ -476,7 +472,7 @@ fail:
 
        fr_thread_detach();
 
-       talloc_free(ctx);
+       talloc_free(sc->thread.ctx);
 
        return NULL;
 }
@@ -494,7 +490,7 @@ int fr_coord_start(uint32_t num_workers, fr_sem_t *sem)
        if (!coord_regs) return 0;
 
        MEM(coord_threads = talloc(NULL, fr_dlist_head_t));
-       fr_dlist_init(coord_threads, fr_schedule_coord_t, entry);
+       fr_dlist_init(coord_threads, fr_schedule_coord_t, thread.entry);
        fr_rb_inline_talloc_init(&coords, fr_coord_t, node, coord_cmp, NULL);
 
        fr_dlist_foreach(coord_regs, fr_coord_reg_t, coord_reg) {
@@ -506,7 +502,7 @@ int fr_coord_start(uint32_t num_workers, fr_sem_t *sem)
                sc->max_workers = num_workers;
                sc->sem = sem;
 
-               if (fr_thread_create(&sc->pthread_id, fr_coordinate_thread, sc) < 0) {
+               if (fr_thread_create(&sc->thread.pthread_id, fr_coordinate_thread, sc) < 0) {
                        talloc_free(sc);
                        PERROR("Failed creating coordinator %s", coord_reg->name);
                        return -1;
@@ -518,7 +514,10 @@ int fr_coord_start(uint32_t num_workers, fr_sem_t *sem)
        /*
         *      Wait for all the coordinators to start.
         */
-       fr_thread_wait(sem, fr_dlist_num_elements(coord_threads));
+       if (fr_thread_wait(sem, coord_threads) < 0) {
+               ERROR("Failed creating coordinator threads");
+               return -1;
+       }
 
        /*
         *      Insert the coordinators in the tree
@@ -544,6 +543,9 @@ void fr_coords_destroy(void)
                fr_rb_iter_delete_inorder(&coords, &iter);
                talloc_free(coord);
        }
+
+       TALLOC_FREE(coord_regs);
+       TALLOC_FREE(coord_threads);
 }
 
 /** Start coordinators in single threaded mode
index 0d89710213e6d3580a424e94f39ea00167afe11d..47c4baaf0ee470420b8c9773e595c709db3c2746 100644 (file)
@@ -38,36 +38,19 @@ RCSID("$Id$")
 
 #include <pthread.h>
 
-/**
- *  Track the child thread status.
- */
-typedef enum fr_schedule_child_status_t {
-       FR_CHILD_FREE = 0,                      //!< child is free
-       FR_CHILD_INITIALIZING,                  //!< initialized, but not running
-       FR_CHILD_RUNNING,                       //!< running, and in the running queue
-       FR_CHILD_EXITED,                        //!< exited, and in the exited queue
-       FR_CHILD_FAIL                           //!< failed, and in the exited queue
-} fr_schedule_child_status_t;
-
 /** Scheduler specific information for worker threads
  *
  * Wraps a fr_worker_t, tracking additional information that
  * the scheduler uses.
  */
 typedef struct {
-       TALLOC_CTX      *ctx;                   //!< our allocation ctx
-       fr_event_list_t *el;                    //!< our event list
-       pthread_t       pthread_id;             //!< the thread of this worker
+       fr_thread_t     thread;                 //!< common thread structure - must be first!
 
-       unsigned int    id;                     //!< a unique ID
        int             uses;                   //!< how many network threads are using it
        fr_time_t       cpu_time;               //!< how much CPU time this worker has used
 
-       fr_dlist_t      entry;                  //!< our entry into the linked list of workers
-
        fr_schedule_t   *sc;                    //!< the scheduler we are running under
 
-       fr_schedule_child_status_t status;      //!< status of the worker
        fr_worker_t     *worker;                //!< the worker data structure
 } fr_schedule_worker_t;
 
@@ -77,16 +60,10 @@ typedef struct {
  * the scheduler uses.
  */
 typedef struct {
-       TALLOC_CTX      *ctx;                   //!< our allocation ctx
-       pthread_t       pthread_id;             //!< the thread of this network
-
-       unsigned int    id;                     //!< a unique ID
-
-       fr_dlist_t      entry;                  //!< our entry into the linked list of networks
+       fr_thread_t     thread;                 //!< common thread structure - must be first!
 
        fr_schedule_t   *sc;                    //!< the scheduler we are running under
 
-       fr_schedule_child_status_t status;      //!< status of the worker
        fr_network_t    *nr;                    //!< the receive data structure
 
        fr_timer_t      *ev;            //!< timer for stats_interval
@@ -141,23 +118,21 @@ int fr_schedule_worker_id(void)
  */
 static void *fr_schedule_worker_thread(void *arg)
 {
-       TALLOC_CTX                      *ctx;
        fr_schedule_worker_t            *sw = talloc_get_type_abort(arg, fr_schedule_worker_t);
        fr_schedule_t                   *sc = sw->sc;
-       fr_schedule_child_status_t      status = FR_CHILD_FAIL;
+       fr_thread_status_t              status = FR_THREAD_FAIL;
        fr_schedule_network_t           *sn;
        char                            worker_name[32];
 
-       worker_id = sw->id;             /* Store the current worker ID */
+       worker_id = sw->thread.id;              /* Store the current worker ID */
 
-       snprintf(worker_name, sizeof(worker_name), "Worker %d", sw->id);
+       snprintf(worker_name, sizeof(worker_name), "Worker %d", sw->thread.id);
 
-       if (fr_thread_setup(&ctx, &sw->el, worker_name) < 0) goto fail;
-       sw->ctx = ctx;
+       if (fr_thread_setup(&sw->thread, worker_name) < 0) goto fail;
 
        INFO("%s - Starting", worker_name);
 
-       sw->worker = fr_worker_alloc(ctx, sw->el, worker_name, sc->log, sc->lvl, &sc->config->worker);
+       sw->worker = fr_worker_alloc(sw->thread.ctx, sw->thread.el, worker_name, sc->log, sc->lvl, &sc->config->worker);
        if (!sw->worker) {
                PERROR("%s - Failed creating worker", worker_name);
                goto fail;
@@ -170,18 +145,18 @@ static void *fr_schedule_worker_thread(void *arg)
                CONF_SECTION    *cs;
                char            section_name[32];
 
-               snprintf(section_name, sizeof(section_name), "%u", sw->id);
+               snprintf(section_name, sizeof(section_name), "%u", sw->thread.id);
 
                cs = cf_section_find(sc->cs, "worker", section_name);
                if (!cs) cs = cf_section_find(sc->cs, "worker", NULL);
 
-               if (sc->worker_thread_instantiate(sw->ctx, sw->el, cs) < 0) {
+               if (sc->worker_thread_instantiate(sw->thread.ctx, sw->thread.el, cs) < 0) {
                        PERROR("%s - Worker thread instantiation failed", worker_name);
                        goto fail;
                }
        }
 
-       sw->status = FR_CHILD_RUNNING;
+       sw->thread.status = FR_THREAD_RUNNING;
 
        /*
         *      Add this worker to all network threads.
@@ -190,7 +165,7 @@ static void *fr_schedule_worker_thread(void *arg)
             sn != NULL;
             sn = fr_dlist_next(&sc->networks, sn)) {
                if (unlikely(fr_network_worker_add(sn->nr, sw->worker) < 0)) {
-                       PERROR("%s - Failed adding worker to network %u", worker_name, sn->id);
+                       PERROR("%s - Failed adding worker to network %u", worker_name, sn->thread.id);
                        goto fail;      /* FIXME - Should maybe try to undo partial adds? */
                }
        }
@@ -207,10 +182,10 @@ static void *fr_schedule_worker_thread(void *arg)
         */
        fr_worker(sw->worker);
 
-       status = FR_CHILD_EXITED;
+       status = FR_THREAD_EXITED;
 
 fail:
-       sw->status = status;
+       sw->thread.status = status;
 
        if (sw->worker) {
                fr_worker_destroy(sw->worker);
@@ -226,14 +201,14 @@ fail:
         *      insertions being done after the thread should have
         *      exited.
         */
-       if (sw->el) fr_event_loop_exit(sw->el, 1);
+       if (sw->thread.el) fr_event_loop_exit(sw->thread.el, 1);
 
        /*
         *      Tell the scheduler we're done.
         */
        sem_post(sc->worker_sem);
 
-       talloc_free(ctx);
+       talloc_free(sw->thread.ctx);
 
        return NULL;
 }
@@ -255,27 +230,24 @@ static void stats_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
  */
 static void *fr_schedule_network_thread(void *arg)
 {
-       TALLOC_CTX                      *ctx;
        fr_schedule_network_t           *sn = talloc_get_type_abort(arg, fr_schedule_network_t);
        fr_schedule_t                   *sc = sn->sc;
-       fr_schedule_child_status_t      status = FR_CHILD_FAIL;
-       fr_event_list_t                 *el;
+       fr_thread_status_t              status = FR_THREAD_FAIL;
        char                            network_name[32];
 
-       snprintf(network_name, sizeof(network_name), "Network %d", sn->id);
+       snprintf(network_name, sizeof(network_name), "Network %d", sn->thread.id);
 
-       if (fr_thread_setup(&ctx, &el, network_name) < 0) goto fail;
-       sn->ctx = ctx;
+       if (fr_thread_setup(&sn->thread, network_name) < 0) goto fail;
 
        INFO("%s - Starting", network_name);
 
-       sn->nr = fr_network_create(ctx, el, network_name, sc->log, sc->lvl, &sc->config->network);
+       sn->nr = fr_network_create(sn->thread.ctx, sn->thread.el, network_name, sc->log, sc->lvl, &sc->config->network);
        if (!sn->nr) {
                PERROR("%s - Failed creating network", network_name);
                goto fail;
        }
 
-       sn->status = FR_CHILD_RUNNING;
+       sn->thread.status = FR_THREAD_RUNNING;
 
        /*
         *      Tell the originator that the thread has started.
@@ -288,7 +260,7 @@ static void *fr_schedule_network_thread(void *arg)
         *      Print out statistics for this network IO handler.
         */
        if (fr_time_delta_ispos(sc->config->stats_interval)) {
-               (void) fr_timer_in(sn, el->tl, &sn->ev, sn->sc->config->stats_interval, false, stats_timer, sn);
+               (void) fr_timer_in(sn, sn->thread.el->tl, &sn->ev, sn->sc->config->stats_interval, false, stats_timer, sn);
        }
        /*
         *      Call the main event processing loop of the network
@@ -297,10 +269,10 @@ static void *fr_schedule_network_thread(void *arg)
         */
        fr_network(sn->nr);
 
-       status = FR_CHILD_EXITED;
+       status = FR_THREAD_EXITED;
 
 fail:
-       sn->status = status;
+       sn->thread.status = status;
 
        INFO("%s - Exiting", network_name);
 
@@ -309,7 +281,7 @@ fail:
         */
        sem_post(sc->network_sem);
 
-       talloc_free(ctx);
+       talloc_free(sn->thread.ctx);
 
        return NULL;
 }
@@ -467,8 +439,8 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
        /*
         *      Create the lists which hold the workers and networks.
         */
-       fr_dlist_init(&sc->workers, fr_schedule_worker_t, entry);
-       fr_dlist_init(&sc->networks, fr_schedule_network_t, entry);
+       fr_dlist_init(&sc->workers, fr_schedule_worker_t, thread.entry);
+       fr_dlist_init(&sc->networks, fr_schedule_network_t, thread.entry);
 
        sc->network_sem = fr_sem_alloc();
        if (!sc->network_sem) {
@@ -501,11 +473,11 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
                        break;
                }
 
-               sn->id = i;
+               sn->thread.id = i;
                sn->sc = sc;
-               sn->status = FR_CHILD_INITIALIZING;
+               sn->thread.status = FR_THREAD_INITIALIZING;
 
-               if (fr_thread_create(&sn->pthread_id, fr_schedule_network_thread, sn) < 0) {
+               if (fr_thread_create(&sn->thread.pthread_id, fr_schedule_network_thread, sn) < 0) {
                        talloc_free(sn);
                        PERROR("Failed creating network %u", i);
                        break;
@@ -519,26 +491,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
         *      they've started, OR there's been a problem and they
         *      can't start.
         */
-       fr_thread_wait(sc->network_sem, fr_dlist_num_elements(&sc->networks));
-
-       /*
-        *      See if all of the networks have started.
-        */
-       for (sn = fr_dlist_head(&sc->networks);
-            sn != NULL;
-            sn = next_sn) {
-               next_sn = fr_dlist_next(&sc->networks, sn);
-
-               if (sn->status != FR_CHILD_RUNNING) {
-                       fr_dlist_remove(&sc->networks, sn);
-                       continue;
-               }
-       }
-
-       /*
-        *      Failed to start some networks, refuse to do anything!
-        */
-       if ((unsigned int)fr_dlist_num_elements(&sc->networks) < sc->config->max_networks) {
+       if (fr_thread_wait(sc->network_sem, &sc->networks) < 0) {
                fr_schedule_destroy(&sc);
                return NULL;
        }
@@ -566,11 +519,11 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
                        break;
                }
 
-               sw->id = i;
+               sw->thread.id = i;
                sw->sc = sc;
-               sw->status = FR_CHILD_INITIALIZING;
+               sw->thread.status = FR_THREAD_INITIALIZING;
 
-               if (fr_thread_create(&sw->pthread_id, fr_schedule_worker_thread, sw) < 0) {
+               if (fr_thread_create(&sw->thread.pthread_id, fr_schedule_worker_thread, sw) < 0) {
                        talloc_free(sw);
                        PERROR("Failed creating worker %u", i);
                        break;
@@ -584,27 +537,7 @@ fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
         *      they've started, OR there's been a problem and they
         *      can't start.
         */
-       fr_thread_wait(sc->worker_sem, fr_dlist_num_elements(&sc->workers));
-
-       /*
-        *      See if all of the workers have started.
-        */
-       for (sw = fr_dlist_head(&sc->workers);
-            sw != NULL;
-            sw = next_sw) {
-
-               next_sw = fr_dlist_next(&sc->workers, sw);
-
-               if (sw->status != FR_CHILD_RUNNING) {
-                       fr_dlist_remove(&sc->workers, sw);
-                       continue;
-               }
-       }
-
-       /*
-        *      Failed to start some workers, refuse to do anything!
-        */
-       if ((unsigned int)fr_dlist_num_elements(&sc->workers) < sc->config->max_workers) {
+       if (fr_thread_wait(sc->worker_sem, &sc->workers) < 0) {
                fr_schedule_destroy(&sc);
                return NULL;
        }
@@ -689,7 +622,7 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
         */
        fr_dlist_foreach(&sc->networks, fr_schedule_network_t, sne) {
                if (fr_network_exit(sne->nr) < 0) {
-                       PERROR("Failed signaling network %i to exit", sne->id);
+                       PERROR("Failed signaling network %i to exit", sne->thread.id);
                }
        }
 
@@ -716,10 +649,10 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
                 *      exited before the main thread cleans up the
                 *      module instances.
                 */
-               if ((ret = pthread_join(sn->pthread_id, NULL)) != 0) {
-                       ERROR("Failed joining network %i: %s", sn->id, fr_syserror(ret));
+               if ((ret = pthread_join(sn->thread.pthread_id, NULL)) != 0) {
+                       ERROR("Failed joining network %i: %s", sn->thread.id, fr_syserror(ret));
                } else {
-                       DEBUG2("Network %i joined (cleaned up)", sn->id);
+                       DEBUG2("Network %i joined (cleaned up)", sn->thread.id);
                }
        }
 
@@ -747,10 +680,10 @@ int fr_schedule_destroy(fr_schedule_t **sc_to_free)
                 *      exited before the main thread cleans up the
                 *      module instances.
                 */
-               if ((ret = pthread_join(sw->pthread_id, NULL)) != 0) {
-                       ERROR("Failed joining worker %i: %s", sw->id, fr_syserror(ret));
+               if ((ret = pthread_join(sw->thread.pthread_id, NULL)) != 0) {
+                       ERROR("Failed joining worker %i: %s", sw->thread.id, fr_syserror(ret));
                } else {
-                       DEBUG2("Worker %i joined (cleaned up)", sw->id);
+                       DEBUG2("Worker %i joined (cleaned up)", sw->thread.id);
                }
        }
 
index 997fc7463b9d957afb627a68e3d8374f1172972b..e4db69f530f23840cef449065fca71d9f892f87c 100644 (file)
@@ -71,34 +71,49 @@ int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
 /** Wait for multiple threads to signal readiness via a semaphore
  *
  * @param[in] sem              semaphore to wait on.
- * @param[in] count            number of times to wait (once per thread).
+ * @param[in] head             head of the list to wait for
+ * @return
+ *     - 0 for success
+ *     - <0 negative number of threads which failed to start
  */
-void fr_thread_wait(fr_sem_t *sem, unsigned int count)
+int fr_thread_wait(fr_sem_t *sem, fr_dlist_head_t *head)
 {
-       unsigned int i;
+       unsigned int i, count;
+       int rcode = 0;
+
+       count = fr_dlist_num_elements(head);
 
        for (i = 0; i < count; i++) {
                SEM_WAIT_INTR(sem);
        }
+
+       /*
+        *      See if all of the threads have started.  If a thread fails, it cleans up any context that was
+        *      allocated for it.
+        */
+       fr_dlist_foreach(head, fr_thread_t, thread) {
+               if (thread->status != FR_THREAD_RUNNING) {
+                       fr_dlist_remove(head, thread);
+                       rcode--;
+               }
+       }
+
+       return rcode;
 }
 
 /** Common setup for child threads: block signals, allocate a talloc context, and create an event list
  *
- * @param[out] out_ctx The talloc ctx we allocate
- * @param[out] out_el  The event list
+ * @param[out] out     structure describing the thread
  * @param[in]  name    Human-readable name used for the talloc context and error messages.
  * @return
  *     - 0 on success.
  *     - <0 on failure
  */
-int fr_thread_setup(TALLOC_CTX **out_ctx, fr_event_list_t **out_el, char const *name)
+int fr_thread_setup(fr_thread_t *out, char const *name)
 {
        TALLOC_CTX      *ctx;
        fr_event_list_t *el;
 
-       *out_ctx = NULL;
-       *out_el = NULL;
-
 #ifndef __APPLE__
        /*
         *      OSX doesn't use pthread_signmask in its setcontext
@@ -127,8 +142,14 @@ int fr_thread_setup(TALLOC_CTX **out_ctx, fr_event_list_t **out_el, char const *
                return -1;
        }
 
-       *out_ctx = ctx;
-       *out_el = el;
+       /*
+        *      Do NOT initialize the entire structure.  Fields like "id" and "entry" have already been
+        *      initialize and used by the main thread coordinator.
+        */
+       out->name = name;
+       out->ctx = ctx;
+       out->el = el;
+       out->status = FR_THREAD_INITIALIZING;
 
        return 0;
 }
index 73a5d4cbdaeffaba141533718610b17cd60fa1d3..540e4a452fda4395edc71db30b62a997be354ffe 100644 (file)
@@ -32,14 +32,40 @@ RCSIDH(thread_h, "$Id$")
 
 #include <pthread.h>
 
+/**
+ *  Track the child thread status.
+ */
+typedef enum fr_thread_status_t {
+       FR_THREAD_FREE = 0,                     //!< child is free
+       FR_THREAD_INITIALIZING,                 //!< initialized, but not running
+       FR_THREAD_RUNNING,                      //!< running, and in the running queue
+       FR_THREAD_EXITED,                       //!< exited, and in the exited queue
+       FR_THREAD_FAIL                          //!< failed, and in the exited queue
+} fr_thread_status_t;
+
+typedef struct {
+       char const              *name;          //!< of this thread
+       int                     id;             //!< unique ID for this thread
+       fr_thread_status_t      status;         //!< running, etc.
+       pthread_t               pthread_id;     //!< of this thread
+
+       TALLOC_CTX              *ctx;           //!< our allocation ctx
+       fr_event_list_t         *el;            //!< our event list
+
+       /*
+        *      This field is owned and managed by the parent coordinator thread.
+        */
+       fr_dlist_t              entry;          //!< entry into the parent linked list of threads
+} fr_thread_t;
+
 typedef void *(*fr_thread_entry_t)(void *);
 
-int    fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg);
+int    fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg) CC_HINT(nonnull(1,2));
 
-void   fr_thread_wait(fr_sem_t *sem, unsigned int count);
+int    fr_thread_wait(fr_sem_t *sem, fr_dlist_head_t *head) CC_HINT(nonnull);
 
-int    fr_thread_setup(TALLOC_CTX **ctx, fr_event_list_t **el, char const *name);
+int    fr_thread_setup(fr_thread_t *out, char const *name) CC_HINT(nonnull);
 
-int    fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el);
+int    fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) CC_HINT(nonnull);
 
 void   fr_thread_detach(void);