]> git.proxmox.com Git - mirror_frr.git/blame - lib/frr_pthread.c
zebra: Switch to using monotime(NULL) for re->uptime
[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"
98f14af8 30
a45dc974 31DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread");
0bbb9e72 32DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
98f14af8 33
a45dc974
QY
34/* default frr_pthread start/stop routine prototypes */
35static void *fpt_run(void *arg);
36static int fpt_halt(struct frr_pthread *fpt, void **res);
98f14af8 37
a45dc974
QY
38/* default frr_pthread attributes */
39struct frr_pthread_attr frr_pthread_attr_default = {
a45dc974
QY
40 .start = fpt_run,
41 .stop = fpt_halt,
a45dc974
QY
42};
43
1ac267a2
DL
44/* list to keep track of all frr_pthreads */
45static pthread_mutex_t frr_pthread_list_mtx = PTHREAD_MUTEX_INITIALIZER;
46static struct list *frr_pthread_list;
a45dc974 47
98f14af8
QY
48/* ------------------------------------------------------------------------ */
49
4d762f26 50void frr_pthread_init(void)
98f14af8 51{
1ac267a2 52 pthread_mutex_lock(&frr_pthread_list_mtx);
d62a17ae 53 {
1ac267a2
DL
54 frr_pthread_list = list_new();
55 frr_pthread_list->del = (void (*)(void *))&frr_pthread_destroy;
d62a17ae 56 }
1ac267a2 57 pthread_mutex_unlock(&frr_pthread_list_mtx);
98f14af8
QY
58}
59
4d762f26 60void frr_pthread_finish(void)
98f14af8 61{
1ac267a2 62 pthread_mutex_lock(&frr_pthread_list_mtx);
d62a17ae 63 {
6a154c88 64 list_delete(&frr_pthread_list);
d62a17ae 65 }
1ac267a2 66 pthread_mutex_unlock(&frr_pthread_list_mtx);
98f14af8
QY
67}
68
d8a8a8de 69struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
57019528 70 const char *name, const char *os_name)
98f14af8 71{
d62a17ae 72 struct frr_pthread *fpt = NULL;
73
a45dc974
QY
74 attr = attr ? attr : &frr_pthread_attr_default;
75
1ac267a2
DL
76 fpt = XCALLOC(MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
77 /* initialize mutex */
78 pthread_mutex_init(&fpt->mtx, NULL);
79 /* create new thread master */
80 fpt->master = thread_master_create(name);
81 /* set attributes */
82 fpt->attr = *attr;
83 name = (name ? name : "Anonymous thread");
84 fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
85 if (os_name)
e77cc2a9 86 strlcpy(fpt->os_name, os_name, OS_THREAD_NAMELEN);
b8dccd94 87 else
e77cc2a9 88 strlcpy(fpt->os_name, name, OS_THREAD_NAMELEN);
1ac267a2
DL
89 /* initialize startup synchronization primitives */
90 fpt->running_cond_mtx = XCALLOC(
91 MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
92 fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
93 sizeof(pthread_cond_t));
94 pthread_mutex_init(fpt->running_cond_mtx, NULL);
95 pthread_cond_init(fpt->running_cond, NULL);
96
97 pthread_mutex_lock(&frr_pthread_list_mtx);
d62a17ae 98 {
1ac267a2 99 listnode_add(frr_pthread_list, fpt);
d62a17ae 100 }
1ac267a2 101 pthread_mutex_unlock(&frr_pthread_list_mtx);
d62a17ae 102
103 return fpt;
98f14af8
QY
104}
105
106void frr_pthread_destroy(struct frr_pthread *fpt)
107{
d62a17ae 108 thread_master_free(fpt->master);
a45dc974 109
d8a8a8de 110 pthread_mutex_destroy(&fpt->mtx);
a45dc974
QY
111 pthread_mutex_destroy(fpt->running_cond_mtx);
112 pthread_cond_destroy(fpt->running_cond);
0a22ddfb 113 XFREE(MTYPE_FRR_PTHREAD, fpt->name);
a45dc974
QY
114 XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
115 XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
d62a17ae 116 XFREE(MTYPE_FRR_PTHREAD, fpt);
98f14af8
QY
117}
118
c80bedb8 119int frr_pthread_set_name(struct frr_pthread *fpt)
d8a8a8de 120{
57019528
CS
121 int ret = 0;
122
e9d938b8
DL
123#ifdef HAVE_PTHREAD_SETNAME_NP
124# ifdef GNU_LINUX
c80bedb8 125 ret = pthread_setname_np(fpt->thread, fpt->os_name);
a64c953a 126# elif defined(__NetBSD__)
c80bedb8 127 ret = pthread_setname_np(fpt->thread, fpt->os_name, NULL);
e9d938b8
DL
128# endif
129#elif defined(HAVE_PTHREAD_SET_NAME_NP)
c80bedb8 130 pthread_set_name_np(fpt->thread, fpt->os_name);
57019528 131#endif
57019528
CS
132
133 return ret;
d8a8a8de
QY
134}
135
a45dc974 136int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
98f14af8 137{
d62a17ae 138 int ret;
98f14af8 139
a45dc974 140 ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
98f14af8 141
a45dc974
QY
142 /*
143 * Per pthread_create(3), the contents of fpt->thread are undefined if
144 * pthread_create() did not succeed. Reset this value to zero.
145 */
d62a17ae 146 if (ret < 0)
147 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
98f14af8 148
d62a17ae 149 return ret;
98f14af8
QY
150}
151
a45dc974 152void frr_pthread_wait_running(struct frr_pthread *fpt)
98f14af8 153{
a45dc974
QY
154 pthread_mutex_lock(fpt->running_cond_mtx);
155 {
156 while (!fpt->running)
157 pthread_cond_wait(fpt->running_cond,
158 fpt->running_cond_mtx);
159 }
160 pthread_mutex_unlock(fpt->running_cond_mtx);
98f14af8
QY
161}
162
a45dc974 163void frr_pthread_notify_running(struct frr_pthread *fpt)
98f14af8 164{
a45dc974
QY
165 pthread_mutex_lock(fpt->running_cond_mtx);
166 {
167 fpt->running = true;
168 pthread_cond_signal(fpt->running_cond);
169 }
170 pthread_mutex_unlock(fpt->running_cond_mtx);
98f14af8
QY
171}
172
a45dc974
QY
173int frr_pthread_stop(struct frr_pthread *fpt, void **result)
174{
175 int ret = (*fpt->attr.stop)(fpt, result);
176 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
177 return ret;
178}
179
4d762f26 180void frr_pthread_stop_all(void)
98f14af8 181{
1ac267a2 182 pthread_mutex_lock(&frr_pthread_list_mtx);
d62a17ae 183 {
1ac267a2
DL
184 struct listnode *n;
185 struct frr_pthread *fpt;
186 for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt))
187 frr_pthread_stop(fpt, NULL);
d62a17ae 188 }
1ac267a2 189 pthread_mutex_unlock(&frr_pthread_list_mtx);
98f14af8 190}
b2140cb7 191
a45dc974
QY
192/*
193 * ----------------------------------------------------------------------------
194 * Default Event Loop
195 * ----------------------------------------------------------------------------
196 */
197
198/* dummy task for sleeper pipe */
199static int fpt_dummy(struct thread *thread)
200{
201 return 0;
202}
203
204/* poison pill task to end event loop */
205static int fpt_finish(struct thread *thread)
206{
207 struct frr_pthread *fpt = THREAD_ARG(thread);
985e36a6 208
a45dc974
QY
209 atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
210 return 0;
211}
212
213/* stop function, called from other threads to halt this one */
214static int fpt_halt(struct frr_pthread *fpt, void **res)
215{
216 thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
217 pthread_join(fpt->thread, res);
a45dc974
QY
218
219 return 0;
220}
221
a6275055
QY
222/*
223 * Entry pthread function & main event loop.
224 *
225 * Upon thread start the following actions occur:
226 *
227 * - frr_pthread's owner field is set to pthread ID.
228 * - All signals are blocked (except for unblockable signals).
229 * - Pthread's threadmaster is set to never handle pending signals
230 * - Poker pipe for poll() is created and queued as I/O source
231 * - The frr_pthread->running_cond condition variable is signalled to indicate
232 * that the previous actions have completed. It is not safe to assume any of
233 * the above have occurred before receiving this signal.
234 *
235 * After initialization is completed, the event loop begins running. Each tick,
236 * the following actions are performed before running the usual event system
237 * tick function:
238 *
239 * - Verify that the running boolean is set
240 * - Verify that there are no pending cancellation requests
241 * - Verify that there are tasks scheduled
242 *
243 * So long as the conditions are met, the event loop tick is run and the
244 * returned task is executed.
245 *
246 * If any of these conditions are not met, the event loop exits, closes the
247 * pipes and dies without running any cleanup functions.
248 */
a45dc974
QY
249static void *fpt_run(void *arg)
250{
251 struct frr_pthread *fpt = arg;
252 fpt->master->owner = pthread_self();
253
254 int sleeper[2];
255 pipe(sleeper);
256 thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL);
257
258 fpt->master->handle_signals = false;
259
c80bedb8 260 frr_pthread_set_name(fpt);
57019528 261
a45dc974
QY
262 frr_pthread_notify_running(fpt);
263
264 struct thread task;
265 while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
a6275055 266 pthread_testcancel();
a45dc974
QY
267 if (thread_fetch(fpt->master, &task)) {
268 thread_call(&task);
269 }
270 }
271
272 close(sleeper[1]);
273 close(sleeper[0]);
274
275 return NULL;
276}