The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
thread.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 2e34607bb921e495aec9bcfbadf19f754b9eb41b $
19 *
20 * @brief Common thread instantiation and detach for worker and coordinator threads
21 * @file io/thread.c
22 *
23 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: 2e34607bb921e495aec9bcfbadf19f754b9eb41b $")
26
27#include <freeradius-devel/io/thread.h>
28#include <freeradius-devel/server/module_rlm.h>
29#include <freeradius-devel/server/virtual_servers.h>
30#include <freeradius-devel/server/main_config.h>
31#include <freeradius-devel/tls/base.h>
32#include <freeradius-devel/unlang/base.h>
33#include <freeradius-devel/util/syserror.h>
34
35#include <signal.h>
36
37/** Create a joinable thread
38 *
39 * @param[out] thread handle that was created by pthread_create.
40 * @param[in] func entry point for the thread.
41 * @param[in] arg Argument to pass to func.
42 * @return
43 * - 0 on success.
44 * - -1 on failure.
45 */
46int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
47{
48 pthread_attr_t attr;
49 int rcode;
50
51 /*
52 * Set the thread to wait around after it's exited so it
53 * can be joined. This is more of a useful mechanism for
54 * the parent to determine if all the threads have exited
55 * so it can continue with a graceful shutdown.
56 */
57 pthread_attr_init(&attr);
58 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
59
60 rcode = pthread_create(thread, &attr, func, arg);
61 if (rcode != 0) {
62 fr_strerror_printf("Failed creating thread: %s", fr_syserror(rcode));
63 pthread_attr_destroy(&attr);
64 return -1;
65 }
66 pthread_attr_destroy(&attr);
67
68 return 0;
69}
70
71/** Wait for multiple threads to signal readiness via a semaphore
72 *
73 * @param[in] sem semaphore to wait on.
74 * @param[in] head head of the list to wait for
75 * @return
76 * - 0 for success
77 * - <0 negative number of threads which failed to start
78 */
80{
81 unsigned int i, count;
82 int rcode = 0;
83
85
86 for (i = 0; i < count; i++) {
87 SEM_WAIT_INTR(sem);
88 }
89
90 /*
91 * See if all of the threads have started. If a thread fails, it cleans up any context that was
92 * allocated for it.
93 */
95 if (thread->status != FR_THREAD_RUNNING) {
96 fr_dlist_remove(head, thread);
97 rcode--;
98 }
99 }
100
101 return rcode;
102}
103
104/** Common setup for child threads: block signals, allocate a talloc context, and create an event list
105 *
106 * @param[out] out structure describing the thread
107 * @param[in] name Human-readable name used for the talloc context and error messages.
108 * @return
109 * - 0 on success.
110 * - <0 on failure
111 */
113{
114 TALLOC_CTX *ctx;
116
117#ifndef __APPLE__
118 /*
119 * OSX doesn't use pthread_signmask in its setcontext
120 * function, and seems to apply the signal mask of the
121 * thread to the entire process when setcontext is
122 * called.
123 */
124 {
125 sigset_t sigset;
126
127 sigfillset(&sigset);
128
129 /*
130 * In debug builds, remove SIGPROF from the set
131 * if we're planning on using gperftools.
132 *
133 * SIGPROF is using during profiling, and must
134 * reach the thread in order for profiling to
135 * work.
136 */
137#if !defined(NDEBUG) && defined(HAVE_GPERFTOOLS_PROFILER_H)
138 sigdelset(&sigset, SIGPROF);
139#endif
140 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
141 }
142#endif
143
144 ctx = talloc_init("%s", name);
145 if (!ctx) {
146 ERROR("%s - Failed allocating memory", name);
147 return -1;
148 }
149
150 el = fr_event_list_alloc(ctx, NULL, NULL);
151 if (!el) {
152 PERROR("%s - Failed creating event list", name);
153 talloc_free(ctx);
154 return -1;
155 }
156
157 /*
158 * Do NOT initialize the entire structure. Fields like "id" and "entry" have already been
159 * initialize and used by the main thread coordinator.
160 */
161 out->name = talloc_strdup(ctx, name);
162 out->ctx = ctx;
163 out->el = el;
164 out->status = FR_THREAD_INITIALIZING;
165
166 return 0;
167}
168
169/** Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS
170 *
171 * @param[in] ctx to allocate thread-specific data in.
172 * @param[in] el event list for this thread.
173 * @return
174 * - 0 on success.
175 * - -1 on failure.
176 */
178{
179#ifdef WITH_TLS
180 /*
181 * Modules may use thread-specific OpenSSL contexts, so initialize this first.
182 */
183 if (fr_openssl_thread_init(main_config->openssl_async_pool_init,
184 main_config->openssl_async_pool_max) < 0) return -1;
185#endif
186
187 if (modules_rlm_thread_instantiate(ctx, el) < 0) return -1;
188
189 if (virtual_servers_thread_instantiate(ctx, el) < 0) return -1;
190
191 if (xlat_thread_instantiate(ctx, el) < 0) return -1;
192
193 if (unlang_thread_instantiate(ctx) < 0) return -1;
194
195 return 0;
196}
197
198/** Detach thread-specific data for modules, virtual servers, xlats
199 *
200 * Calls detach in reverse order of instantiation.
201 */
209
210
211/** Signal the parent that we're done.
212 *
213 * @param[out] thread which is starting
214 * @param[in] sem semaphore to signal.
215 */
217{
218 thread->status = FR_THREAD_RUNNING;
219
220 INFO("%s - Starting", thread->name);
221
222 sem_post(sem);
223}
224
225/** Signal the parent that we're done.
226 *
227 * @param[out] thread which is exiting
228 * @param[in] status to write
229 * @param[in] sem semaphore to signal.
230 */
232{
233 /*
234 * Maybe nothing was initialized, so we don't need to do anything.
235 */
236 if (thread->status == FR_THREAD_FREE) return;
237
238 INFO("%s - Exiting", thread->name);
239
240 thread->status = status;
241
242 /*
243 * Not looping at this point, but may catch timer/fd
244 * insertions being done after the thread should have
245 * exited.
246 */
247 if (thread->el) fr_event_loop_exit(thread->el, 1);
248
249 TALLOC_FREE(thread->ctx);
250
251 sem_post(sem);
252}
#define RCSID(id)
Definition build.h:603
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:98
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
Head of a doubly linked list.
Definition dlist.h:51
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:233
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition event.c:2551
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2398
Stores all information relating to an event list.
Definition event.c:375
main_config_t const * main_config
Main server configuration.
Definition main_config.c:56
void modules_rlm_thread_detach(void)
Frees thread-specific data for all registered backend modules.
Definition module_rlm.c:967
int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Allocates thread-specific data for all registered backend modules.
Definition module_rlm.c:980
int modules_rlm_coord_detach(void)
Runs the coord_detach method of all registered backend modules.
Definition module_rlm.c:999
#define INFO(fmt,...)
Definition radict.c:67
static char const * name
#define SEM_WAIT_INTR(_x)
Definition semaphore.h:56
sem_t fr_sem_t
Definition semaphore.h:53
Signals that can be sent to a request.
return count
Definition module.c:155
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
void fr_thread_start(fr_thread_t *thread, fr_sem_t *sem)
Signal the parent that we're done.
Definition thread.c:216
int fr_thread_wait_list(fr_sem_t *sem, fr_dlist_head_t *head)
Wait for multiple threads to signal readiness via a semaphore.
Definition thread.c:79
int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
Create a joinable thread.
Definition thread.c:46
int fr_thread_setup(fr_thread_t *out, char const *name)
Common setup for child threads: block signals, allocate a talloc context, and create an event list.
Definition thread.c:112
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS.
Definition thread.c:177
void fr_thread_detach(void)
Detach thread-specific data for modules, virtual servers, xlats.
Definition thread.c:202
void fr_thread_exit(fr_thread_t *thread, fr_thread_status_t status, fr_sem_t *sem)
Signal the parent that we're done.
Definition thread.c:231
fr_thread_status_t status
running, etc.
Definition thread.h:49
char const * name
of this thread
Definition thread.h:47
fr_thread_status_t
Track the child thread status.
Definition thread.h:38
@ FR_THREAD_RUNNING
running, and in the running queue
Definition thread.h:41
@ FR_THREAD_INITIALIZING
initialized, but not running
Definition thread.h:40
@ FR_THREAD_FREE
child is free
Definition thread.h:39
fr_event_list_t * el
our event list
Definition thread.h:53
TALLOC_CTX * ctx
our allocation ctx
Definition thread.h:52
void *(* fr_thread_entry_t)(void *)
Definition thread.h:61
static fr_event_list_t * el
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
Definition interpret.c:69
void xlat_thread_detach(void)
Destroy any thread specific xlat instances.
Definition xlat_inst.c:486
static fr_slen_t head
Definition xlat.h:410
int xlat_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Create thread specific instance tree and create thread instances.
Definition xlat_inst.c:441
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_sbuff_err_t char ** out
Definition value.h:1061
void virtual_servers_thread_detach(void)
Free thread-specific data for all process modules and listeners.
int virtual_servers_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Perform thread instantiation for all process modules and listeners.