]> git.proxmox.com Git - mirror_frr.git/blame - lib/frr_pthread.c
bgpd: update routemap scripting example
[mirror_frr.git] / lib / frr_pthread.c
CommitLineData
98f14af8 1/*
a45dc974 2 * Utilities and interfaces for managing POSIX threads within FRR.
d8a8a8de 3 * Copyright (C) 2017 Cumulus Networks, Inc.
896014f4
DL
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
98f14af8
QY
18 */
19
20#include <zebra.h>
21#include <pthread.h>
324be174
DL
22#ifdef HAVE_PTHREAD_NP_H
23#include <pthread_np.h>
24#endif
b2140cb7 25#include <sched.h>
98f14af8
QY
26
27#include "frr_pthread.h"
28#include "memory.h"
1ac267a2 29#include "linklist.h"
0bdeb5e5 30#include "zlog.h"
912d45a1 31#include "libfrr_trace.h"
98f14af8 32
eaf58ba9
DL
33DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread")
34DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives")
98f14af8 35
a45dc974
QY
36/* default frr_pthread start/stop routine prototypes */
37static void *fpt_run(void *arg);
38static int fpt_halt(struct frr_pthread *fpt, void **res);
98f14af8 39
9af949cc
QY
40/* misc sigs */
41static void frr_pthread_destroy_nolock(struct frr_pthread *fpt);
42
a45dc974 43/* default frr_pthread attributes */
2b64873d 44const struct frr_pthread_attr frr_pthread_attr_default = {
a45dc974
QY
45 .start = fpt_run,
46 .stop = fpt_halt,
a45dc974
QY
47};
48
1ac267a2
DL
49/* list to keep track of all frr_pthreads */
50static pthread_mutex_t frr_pthread_list_mtx = PTHREAD_MUTEX_INITIALIZER;
51static struct list *frr_pthread_list;
a45dc974 52
98f14af8
QY
53/* ------------------------------------------------------------------------ */
54
4d762f26 55void frr_pthread_init(void)
98f14af8 56{
00dffa8c 57 frr_with_mutex(&frr_pthread_list_mtx) {
1ac267a2 58 frr_pthread_list = list_new();
d62a17ae 59 }
98f14af8
QY
60}
61
4d762f26 62void frr_pthread_finish(void)
98f14af8 63{
54baf432
QY
64 frr_pthread_stop_all();
65
00dffa8c 66 frr_with_mutex(&frr_pthread_list_mtx) {
9af949cc
QY
67 struct listnode *n, *nn;
68 struct frr_pthread *fpt;
69
70 for (ALL_LIST_ELEMENTS(frr_pthread_list, n, nn, fpt)) {
71 listnode_delete(frr_pthread_list, fpt);
72 frr_pthread_destroy_nolock(fpt);
73 }
74
6a154c88 75 list_delete(&frr_pthread_list);
d62a17ae 76 }
98f14af8
QY
77}
78
2b64873d 79struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
57019528 80 const char *name, const char *os_name)
98f14af8 81{
d62a17ae 82 struct frr_pthread *fpt = NULL;
83
a45dc974
QY
84 attr = attr ? attr : &frr_pthread_attr_default;
85
1ac267a2
DL
86 fpt = XCALLOC(MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
87 /* initialize mutex */
88 pthread_mutex_init(&fpt->mtx, NULL);
89 /* create new thread master */
90 fpt->master = thread_master_create(name);
91 /* set attributes */
92 fpt->attr = *attr;
93 name = (name ? name : "Anonymous thread");
94 fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
95 if (os_name)
e77cc2a9 96 strlcpy(fpt->os_name, os_name, OS_THREAD_NAMELEN);
b8dccd94 97 else
e77cc2a9 98 strlcpy(fpt->os_name, name, OS_THREAD_NAMELEN);
1ac267a2
DL
99 /* initialize startup synchronization primitives */
100 fpt->running_cond_mtx = XCALLOC(
101 MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
102 fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
103 sizeof(pthread_cond_t));
104 pthread_mutex_init(fpt->running_cond_mtx, NULL);
105 pthread_cond_init(fpt->running_cond, NULL);
106
00dffa8c 107 frr_with_mutex(&frr_pthread_list_mtx) {
1ac267a2 108 listnode_add(frr_pthread_list, fpt);
d62a17ae 109 }
d62a17ae 110
111 return fpt;
98f14af8
QY
112}
113
9af949cc 114static void frr_pthread_destroy_nolock(struct frr_pthread *fpt)
98f14af8 115{
54baf432 116 thread_master_free(fpt->master);
d8a8a8de 117 pthread_mutex_destroy(&fpt->mtx);
a45dc974
QY
118 pthread_mutex_destroy(fpt->running_cond_mtx);
119 pthread_cond_destroy(fpt->running_cond);
0a22ddfb 120 XFREE(MTYPE_FRR_PTHREAD, fpt->name);
a45dc974
QY
121 XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
122 XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
d62a17ae 123 XFREE(MTYPE_FRR_PTHREAD, fpt);
98f14af8
QY
124}
125
9af949cc
QY
126void frr_pthread_destroy(struct frr_pthread *fpt)
127{
128 frr_with_mutex(&frr_pthread_list_mtx) {
129 listnode_delete(frr_pthread_list, fpt);
130 }
131
132 frr_pthread_destroy_nolock(fpt);
133}
134
c80bedb8 135int frr_pthread_set_name(struct frr_pthread *fpt)
d8a8a8de 136{
57019528
CS
137 int ret = 0;
138
e9d938b8
DL
139#ifdef HAVE_PTHREAD_SETNAME_NP
140# ifdef GNU_LINUX
c80bedb8 141 ret = pthread_setname_np(fpt->thread, fpt->os_name);
a64c953a 142# elif defined(__NetBSD__)
c80bedb8 143 ret = pthread_setname_np(fpt->thread, fpt->os_name, NULL);
e9d938b8
DL
144# endif
145#elif defined(HAVE_PTHREAD_SET_NAME_NP)
c80bedb8 146 pthread_set_name_np(fpt->thread, fpt->os_name);
57019528 147#endif
57019528
CS
148
149 return ret;
d8a8a8de
QY
150}
151
3e41733f
DL
152static void *frr_pthread_inner(void *arg)
153{
154 struct frr_pthread *fpt = arg;
155
156 rcu_thread_start(fpt->rcu_thread);
157 return fpt->attr.start(fpt);
158}
159
a45dc974 160int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
98f14af8 161{
d62a17ae 162 int ret;
f4635e33
MS
163 sigset_t oldsigs, blocksigs;
164
165 /* Ensure we never handle signals on a background thread by blocking
166 * everything here (new thread inherits signal mask)
167 */
168 sigfillset(&blocksigs);
169 pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs);
98f14af8 170
c7bb4f00 171 frrtrace(1, frr_libfrr, frr_pthread_run, fpt->name);
87879a5e 172
3e41733f
DL
173 fpt->rcu_thread = rcu_thread_prepare();
174 ret = pthread_create(&fpt->thread, attr, frr_pthread_inner, fpt);
98f14af8 175
f4635e33
MS
176 /* Restore caller's signals */
177 pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
178
a45dc974
QY
179 /*
180 * Per pthread_create(3), the contents of fpt->thread are undefined if
181 * pthread_create() did not succeed. Reset this value to zero.
182 */
3e41733f
DL
183 if (ret < 0) {
184 rcu_thread_unprepare(fpt->rcu_thread);
d62a17ae 185 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
3e41733f 186 }
98f14af8 187
d62a17ae 188 return ret;
98f14af8
QY
189}
190
a45dc974 191void frr_pthread_wait_running(struct frr_pthread *fpt)
98f14af8 192{
00dffa8c 193 frr_with_mutex(fpt->running_cond_mtx) {
a45dc974
QY
194 while (!fpt->running)
195 pthread_cond_wait(fpt->running_cond,
196 fpt->running_cond_mtx);
197 }
98f14af8
QY
198}
199
a45dc974 200void frr_pthread_notify_running(struct frr_pthread *fpt)
98f14af8 201{
00dffa8c 202 frr_with_mutex(fpt->running_cond_mtx) {
a45dc974
QY
203 fpt->running = true;
204 pthread_cond_signal(fpt->running_cond);
205 }
98f14af8
QY
206}
207
a45dc974
QY
208int frr_pthread_stop(struct frr_pthread *fpt, void **result)
209{
c7bb4f00 210 frrtrace(1, frr_libfrr, frr_pthread_stop, fpt->name);
87879a5e 211
a45dc974
QY
212 int ret = (*fpt->attr.stop)(fpt, result);
213 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
214 return ret;
215}
216
4d762f26 217void frr_pthread_stop_all(void)
98f14af8 218{
00dffa8c 219 frr_with_mutex(&frr_pthread_list_mtx) {
1ac267a2
DL
220 struct listnode *n;
221 struct frr_pthread *fpt;
54baf432
QY
222 for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt)) {
223 if (atomic_load_explicit(&fpt->running,
224 memory_order_relaxed))
225 frr_pthread_stop(fpt, NULL);
226 }
d62a17ae 227 }
98f14af8 228}
b2140cb7 229
a45dc974
QY
230/*
231 * ----------------------------------------------------------------------------
232 * Default Event Loop
233 * ----------------------------------------------------------------------------
234 */
235
236/* dummy task for sleeper pipe */
237static int fpt_dummy(struct thread *thread)
238{
239 return 0;
240}
241
242/* poison pill task to end event loop */
243static int fpt_finish(struct thread *thread)
244{
245 struct frr_pthread *fpt = THREAD_ARG(thread);
985e36a6 246
a45dc974
QY
247 atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
248 return 0;
249}
250
251/* stop function, called from other threads to halt this one */
252static int fpt_halt(struct frr_pthread *fpt, void **res)
253{
254 thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
255 pthread_join(fpt->thread, res);
a45dc974
QY
256
257 return 0;
258}
259
a6275055
QY
260/*
261 * Entry pthread function & main event loop.
262 *
263 * Upon thread start the following actions occur:
264 *
265 * - frr_pthread's owner field is set to pthread ID.
266 * - All signals are blocked (except for unblockable signals).
267 * - Pthread's threadmaster is set to never handle pending signals
268 * - Poker pipe for poll() is created and queued as I/O source
269 * - The frr_pthread->running_cond condition variable is signalled to indicate
270 * that the previous actions have completed. It is not safe to assume any of
271 * the above have occurred before receiving this signal.
272 *
273 * After initialization is completed, the event loop begins running. Each tick,
274 * the following actions are performed before running the usual event system
275 * tick function:
276 *
277 * - Verify that the running boolean is set
278 * - Verify that there are no pending cancellation requests
279 * - Verify that there are tasks scheduled
280 *
281 * So long as the conditions are met, the event loop tick is run and the
282 * returned task is executed.
283 *
284 * If any of these conditions are not met, the event loop exits, closes the
285 * pipes and dies without running any cleanup functions.
286 */
a45dc974
QY
287static void *fpt_run(void *arg)
288{
289 struct frr_pthread *fpt = arg;
290 fpt->master->owner = pthread_self();
291
0bdeb5e5
DL
292 zlog_tls_buffer_init();
293
a45dc974
QY
294 int sleeper[2];
295 pipe(sleeper);
296 thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL);
297
298 fpt->master->handle_signals = false;
299
c80bedb8 300 frr_pthread_set_name(fpt);
57019528 301
a45dc974
QY
302 frr_pthread_notify_running(fpt);
303
304 struct thread task;
305 while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
a6275055 306 pthread_testcancel();
a45dc974
QY
307 if (thread_fetch(fpt->master, &task)) {
308 thread_call(&task);
309 }
310 }
311
312 close(sleeper[1]);
313 close(sleeper[0]);
314
0bdeb5e5
DL
315 zlog_tls_buffer_fini();
316
a45dc974
QY
317 return NULL;
318}