The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 2ef38705fdabec2e013e515ea5048cd3a7a13210 $
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: 2ef38705fdabec2e013e515ea5048cd3a7a13210 $")
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 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
129 }
130#endif
131
132 ctx = talloc_init("%s", name);
133 if (!ctx) {
134 ERROR("%s - Failed allocating memory", name);
135 return -1;
136 }
137
138 el = fr_event_list_alloc(ctx, NULL, NULL);
139 if (!el) {
140 PERROR("%s - Failed creating event list", name);
141 talloc_free(ctx);
142 return -1;
143 }
144
145 /*
146 * Do NOT initialize the entire structure. Fields like "id" and "entry" have already been
147 * initialize and used by the main thread coordinator.
148 */
149 out->name = talloc_strdup(ctx, name);
150 out->ctx = ctx;
151 out->el = el;
152 out->status = FR_THREAD_INITIALIZING;
153
154 return 0;
155}
156
157/** Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS
158 *
159 * @param[in] ctx to allocate thread-specific data in.
160 * @param[in] el event list for this thread.
161 * @return
162 * - 0 on success.
163 * - -1 on failure.
164 */
166{
167#ifdef WITH_TLS
168 /*
169 * Modules may use thread-specific OpenSSL contexts, so initialize this first.
170 */
171 if (fr_openssl_thread_init(main_config->openssl_async_pool_init,
172 main_config->openssl_async_pool_max) < 0) return -1;
173#endif
174
175 if (modules_rlm_thread_instantiate(ctx, el) < 0) return -1;
176
177 if (virtual_servers_thread_instantiate(ctx, el) < 0) return -1;
178
179 if (xlat_thread_instantiate(ctx, el) < 0) return -1;
180
181 if (unlang_thread_instantiate(ctx) < 0) return -1;
182
183 return 0;
184}
185
186/** Detach thread-specific data for modules, virtual servers, xlats
187 *
188 * Calls detach in reverse order of instantiation.
189 */
196
197
198/** Signal the parent that we're done.
199 *
200 * @param[out] thread which is starting
201 * @param[in] sem semaphore to signal.
202 */
204{
205 thread->status = FR_THREAD_RUNNING;
206
207 INFO("%s - Starting", thread->name);
208
209 sem_post(sem);
210}
211
212/** Signal the parent that we're done.
213 *
214 * @param[out] thread which is exiting
215 * @param[in] status to write
216 * @param[in] sem semaphore to signal.
217 */
219{
220 /*
221 * Maybe nothing was initialized, so we don't need to do anything.
222 */
223 if (thread->status == FR_THREAD_FREE) return;
224
225 INFO("%s - Exiting", thread->name);
226
227 thread->status = status;
228
229 /*
230 * Not looping at this point, but may catch timer/fd
231 * insertions being done after the thread should have
232 * exited.
233 */
234 if (thread->el) fr_event_loop_exit(thread->el, 1);
235
236 TALLOC_FREE(thread->ctx);
237
238 sem_post(sem);
239}
#define RCSID(id)
Definition build.h:488
#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:228
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:2506
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2355
Stores all information relating to an event list.
Definition event.c:377
main_config_t const * main_config
Main server configuration.
Definition main_config.c:58
void modules_rlm_thread_detach(void)
Frees thread-specific data for all registered backend modules.
Definition module_rlm.c:960
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:973
#define INFO(fmt,...)
Definition radict.c:63
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:142
void fr_thread_start(fr_thread_t *thread, fr_sem_t *sem)
Signal the parent that we're done.
Definition thread.c:203
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:165
void fr_thread_detach(void)
Detach thread-specific data for modules, virtual servers, xlats.
Definition thread.c:190
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:218
fr_thread_status_t status
running, etc.
Definition thread.h:49
char const * name
of this thread
Definition thread.h:47
fr_event_list_t * el
our event list
Definition thread.h:53
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
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 compile.c:2295
void xlat_thread_detach(void)
Destroy any thread specific xlat instances.
Definition xlat_inst.c:486
static fr_slen_t head
Definition xlat.h:420
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 size_t char ** out
Definition value.h:1030
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.