2 * Utilities and interfaces for managing POSIX threads within FRR.
3 * Copyright (C) 2017 Cumulus Networks, Inc.
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.
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.
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
24 #include "frr_pthread.h"
28 DEFINE_MTYPE(LIB
, FRR_PTHREAD
, "FRR POSIX Thread");
29 DEFINE_MTYPE(LIB
, PTHREAD_PRIM
, "POSIX synchronization primitives");
31 /* id for next created pthread */
32 static _Atomic
uint32_t next_id
= 0;
34 /* default frr_pthread start/stop routine prototypes */
35 static void *fpt_run(void *arg
);
36 static int fpt_halt(struct frr_pthread
*fpt
, void **res
);
38 /* default frr_pthread attributes */
39 struct frr_pthread_attr frr_pthread_attr_default
= {
45 /* hash table to keep track of all frr_pthreads */
46 static struct hash
*frr_pthread_hash
;
47 static pthread_mutex_t frr_pthread_hash_mtx
= PTHREAD_MUTEX_INITIALIZER
;
49 /* frr_pthread_hash->hash_cmp */
50 static int frr_pthread_hash_cmp(const void *value1
, const void *value2
)
52 const struct frr_pthread
*tq1
= value1
;
53 const struct frr_pthread
*tq2
= value2
;
55 return (tq1
->attr
.id
== tq2
->attr
.id
);
58 /* frr_pthread_hash->hash_key */
59 static unsigned int frr_pthread_hash_key(void *value
)
61 return ((struct frr_pthread
*)value
)->attr
.id
;
64 /* ------------------------------------------------------------------------ */
66 void frr_pthread_init()
68 pthread_mutex_lock(&frr_pthread_hash_mtx
);
70 frr_pthread_hash
= hash_create(frr_pthread_hash_key
,
71 frr_pthread_hash_cmp
, NULL
);
73 pthread_mutex_unlock(&frr_pthread_hash_mtx
);
76 void frr_pthread_finish()
78 pthread_mutex_lock(&frr_pthread_hash_mtx
);
80 hash_clean(frr_pthread_hash
,
81 (void (*)(void *))frr_pthread_destroy
);
82 hash_free(frr_pthread_hash
);
84 pthread_mutex_unlock(&frr_pthread_hash_mtx
);
87 struct frr_pthread
*frr_pthread_new(struct frr_pthread_attr
*attr
,
88 const char *name
, const char *os_name
)
90 static struct frr_pthread holder
= {};
91 struct frr_pthread
*fpt
= NULL
;
93 attr
= attr
? attr
: &frr_pthread_attr_default
;
95 pthread_mutex_lock(&frr_pthread_hash_mtx
);
97 holder
.attr
.id
= attr
->id
;
99 if (!hash_lookup(frr_pthread_hash
, &holder
)) {
100 fpt
= XCALLOC(MTYPE_FRR_PTHREAD
,
101 sizeof(struct frr_pthread
));
102 /* initialize mutex */
103 pthread_mutex_init(&fpt
->mtx
, NULL
);
104 /* create new thread master */
105 fpt
->master
= thread_master_create(name
);
108 name
= (name
? name
: "Anonymous thread");
109 fpt
->name
= XSTRDUP(MTYPE_FRR_PTHREAD
, name
);
111 snprintf(fpt
->os_name
, OS_THREAD_NAMELEN
,
113 if (attr
== &frr_pthread_attr_default
)
114 fpt
->attr
.id
= frr_pthread_get_id();
115 /* initialize startup synchronization primitives */
116 fpt
->running_cond_mtx
= XCALLOC(
117 MTYPE_PTHREAD_PRIM
, sizeof(pthread_mutex_t
));
118 fpt
->running_cond
= XCALLOC(MTYPE_PTHREAD_PRIM
,
119 sizeof(pthread_cond_t
));
120 pthread_mutex_init(fpt
->running_cond_mtx
, NULL
);
121 pthread_cond_init(fpt
->running_cond
, NULL
);
123 /* insert into global thread hash */
124 hash_get(frr_pthread_hash
, fpt
, hash_alloc_intern
);
127 pthread_mutex_unlock(&frr_pthread_hash_mtx
);
132 void frr_pthread_destroy(struct frr_pthread
*fpt
)
134 thread_master_free(fpt
->master
);
136 pthread_mutex_destroy(&fpt
->mtx
);
137 pthread_mutex_destroy(fpt
->running_cond_mtx
);
138 pthread_cond_destroy(fpt
->running_cond
);
140 XFREE(MTYPE_FRR_PTHREAD
, fpt
->name
);
141 XFREE(MTYPE_PTHREAD_PRIM
, fpt
->running_cond_mtx
);
142 XFREE(MTYPE_PTHREAD_PRIM
, fpt
->running_cond
);
143 XFREE(MTYPE_FRR_PTHREAD
, fpt
);
146 int frr_pthread_set_name(struct frr_pthread
*fpt
, const char *name
,
152 pthread_mutex_lock(&fpt
->mtx
);
155 XFREE(MTYPE_FRR_PTHREAD
, fpt
->name
);
156 fpt
->name
= XSTRDUP(MTYPE_FRR_PTHREAD
, name
);
158 pthread_mutex_unlock(&fpt
->mtx
);
159 thread_master_set_name(fpt
->master
, name
);
163 pthread_mutex_lock(&fpt
->mtx
);
164 snprintf(fpt
->os_name
, OS_THREAD_NAMELEN
, "%s", os_name
);
165 pthread_mutex_unlock(&fpt
->mtx
);
167 ret
= pthread_setname_np(fpt
->thread
, fpt
->os_name
);
168 #elif defined(OPEN_BSD)
169 ret
= pthread_set_name_np(fpt
->thread
, fpt
->os_name
);
176 struct frr_pthread
*frr_pthread_get(uint32_t id
)
178 static struct frr_pthread holder
= {};
179 struct frr_pthread
*fpt
;
181 pthread_mutex_lock(&frr_pthread_hash_mtx
);
184 fpt
= hash_lookup(frr_pthread_hash
, &holder
);
186 pthread_mutex_unlock(&frr_pthread_hash_mtx
);
191 int frr_pthread_run(struct frr_pthread
*fpt
, const pthread_attr_t
*attr
)
195 ret
= pthread_create(&fpt
->thread
, attr
, fpt
->attr
.start
, fpt
);
198 * Per pthread_create(3), the contents of fpt->thread are undefined if
199 * pthread_create() did not succeed. Reset this value to zero.
202 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
207 void frr_pthread_wait_running(struct frr_pthread
*fpt
)
209 pthread_mutex_lock(fpt
->running_cond_mtx
);
211 while (!fpt
->running
)
212 pthread_cond_wait(fpt
->running_cond
,
213 fpt
->running_cond_mtx
);
215 pthread_mutex_unlock(fpt
->running_cond_mtx
);
218 void frr_pthread_notify_running(struct frr_pthread
*fpt
)
220 pthread_mutex_lock(fpt
->running_cond_mtx
);
223 pthread_cond_signal(fpt
->running_cond
);
225 pthread_mutex_unlock(fpt
->running_cond_mtx
);
228 int frr_pthread_stop(struct frr_pthread
*fpt
, void **result
)
230 int ret
= (*fpt
->attr
.stop
)(fpt
, result
);
231 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
236 * Callback for hash_iterate to stop all frr_pthread's.
238 static void frr_pthread_stop_all_iter(struct hash_backet
*hb
, void *arg
)
240 struct frr_pthread
*fpt
= hb
->data
;
241 frr_pthread_stop(fpt
, NULL
);
244 void frr_pthread_stop_all()
246 pthread_mutex_lock(&frr_pthread_hash_mtx
);
248 hash_iterate(frr_pthread_hash
, frr_pthread_stop_all_iter
, NULL
);
250 pthread_mutex_unlock(&frr_pthread_hash_mtx
);
253 uint32_t frr_pthread_get_id(void)
255 _Atomic
uint32_t nxid
;
256 nxid
= atomic_fetch_add_explicit(&next_id
, 1, memory_order_seq_cst
);
257 /* just a sanity check, this should never happen */
258 assert(nxid
<= (UINT32_MAX
- 1));
262 void frr_pthread_yield(void)
268 * ----------------------------------------------------------------------------
270 * ----------------------------------------------------------------------------
273 /* dummy task for sleeper pipe */
274 static int fpt_dummy(struct thread
*thread
)
279 /* poison pill task to end event loop */
280 static int fpt_finish(struct thread
*thread
)
282 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
284 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
288 /* stop function, called from other threads to halt this one */
289 static int fpt_halt(struct frr_pthread
*fpt
, void **res
)
291 thread_add_event(fpt
->master
, &fpt_finish
, fpt
, 0, NULL
);
292 pthread_join(fpt
->thread
, res
);
298 * Entry pthread function & main event loop.
300 * Upon thread start the following actions occur:
302 * - frr_pthread's owner field is set to pthread ID.
303 * - All signals are blocked (except for unblockable signals).
304 * - Pthread's threadmaster is set to never handle pending signals
305 * - Poker pipe for poll() is created and queued as I/O source
306 * - The frr_pthread->running_cond condition variable is signalled to indicate
307 * that the previous actions have completed. It is not safe to assume any of
308 * the above have occurred before receiving this signal.
310 * After initialization is completed, the event loop begins running. Each tick,
311 * the following actions are performed before running the usual event system
314 * - Verify that the running boolean is set
315 * - Verify that there are no pending cancellation requests
316 * - Verify that there are tasks scheduled
318 * So long as the conditions are met, the event loop tick is run and the
319 * returned task is executed.
321 * If any of these conditions are not met, the event loop exits, closes the
322 * pipes and dies without running any cleanup functions.
324 static void *fpt_run(void *arg
)
326 struct frr_pthread
*fpt
= arg
;
327 fpt
->master
->owner
= pthread_self();
331 thread_add_read(fpt
->master
, &fpt_dummy
, NULL
, sleeper
[0], NULL
);
333 fpt
->master
->handle_signals
= false;
336 frr_pthread_set_name(fpt
, NULL
, fpt
->os_name
);
338 frr_pthread_notify_running(fpt
);
341 while (atomic_load_explicit(&fpt
->running
, memory_order_relaxed
)) {
342 pthread_testcancel();
343 if (thread_fetch(fpt
->master
, &task
)) {