Line data Source code
1 : /*
2 : * Utilities and interfaces for managing POSIX threads within FRR.
3 : * Copyright (C) 2017 Cumulus Networks, Inc.
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
18 : */
19 :
20 : #ifndef _FRR_PTHREAD_H
21 : #define _FRR_PTHREAD_H
22 :
23 : #include <pthread.h>
24 : #include "frratomic.h"
25 : #include "memory.h"
26 : #include "frrcu.h"
27 : #include "thread.h"
28 :
29 : #ifdef __cplusplus
30 : extern "C" {
31 : #endif
32 :
33 : #define OS_THREAD_NAMELEN 16
34 :
35 : struct frr_pthread;
36 : struct frr_pthread_attr;
37 :
38 : struct frr_pthread_attr {
39 : void *(*start)(void *);
40 : int (*stop)(struct frr_pthread *, void **);
41 : };
42 :
43 : struct frr_pthread {
44 :
45 : /*
46 : * Mutex protecting this structure. Must be taken for reading some
47 : * fields, denoted by a 'Requires: mtx'.
48 : */
49 : pthread_mutex_t mtx;
50 :
51 : /* pthread id */
52 : pthread_t thread;
53 :
54 : struct rcu_thread *rcu_thread;
55 :
56 : /* thread master for this pthread's thread.c event loop */
57 : struct thread_master *master;
58 :
59 : /* caller-specified data; start & stop funcs, name, id */
60 : struct frr_pthread_attr attr;
61 :
62 : /*
63 : * Notification mechanism for allowing pthreads to notify their parents
64 : * when they are ready to do work. This mechanism has two associated
65 : * functions:
66 : *
67 : * - frr_pthread_wait_running()
68 : * This function should be called by the spawning thread after
69 : * frr_pthread_run(). It safely waits until the spawned thread
70 : * indicates that is ready to do work by posting to the condition
71 : * variable.
72 : *
73 : * - frr_pthread_notify_running()
74 : * This function should be called by the spawned thread when it is
75 : * ready to do work. It will wake up any threads waiting on the
76 : * previously described condition.
77 : */
78 : pthread_cond_t *running_cond;
79 : pthread_mutex_t *running_cond_mtx;
80 : atomic_bool running;
81 :
82 : /*
83 : * Fake thread-specific storage. No constraints on usage. Helpful when
84 : * creating reentrant pthread implementations. Can be used to pass
85 : * argument to pthread entry function.
86 : *
87 : * Requires: mtx
88 : */
89 : void *data;
90 :
91 : /*
92 : * Human-readable thread name.
93 : *
94 : * Requires: mtx
95 : */
96 : char *name;
97 :
98 : /* Used in pthread_set_name max 16 characters */
99 : char os_name[OS_THREAD_NAMELEN];
100 : };
101 :
102 : extern const struct frr_pthread_attr frr_pthread_attr_default;
103 :
104 : /*
105 : * Initializes this module.
106 : *
107 : * Must be called before using any of the other functions.
108 : */
109 : void frr_pthread_init(void);
110 :
111 : /*
112 : * Uninitializes this module.
113 : *
114 : * Destroys all registered frr_pthread's and internal data structures.
115 : *
116 : * It is safe to call frr_pthread_init() after this function to reinitialize
117 : * the module.
118 : */
119 : void frr_pthread_finish(void);
120 :
121 : /*
122 : * Creates a new frr_pthread with the given attributes.
123 : *
124 : * The 'attr' argument should be filled out with the desired attributes,
125 : * including ID, start and stop functions and the desired name. Alternatively,
126 : * if attr is NULL, the default attributes will be used. The pthread will be
127 : * set up to run a basic threadmaster loop and the name will be "Anonymous".
128 : * Scheduling tasks onto the threadmaster in the 'master' field of the returned
129 : * frr_pthread will cause them to run on that pthread.
130 : *
131 : * @param attr - the thread attributes
132 : * @param name - Human-readable name
133 : * @param os_name - 16 characters (including '\0') thread name to set in os,
134 : * @return the created frr_pthread upon success, or NULL upon failure
135 : */
136 : struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
137 : const char *name, const char *os_name);
138 :
139 : /*
140 : * Changes the name of the frr_pthread as reported by the operating
141 : * system.
142 : *
143 : * @param fpt - the frr_pthread to operate on
144 : * @return - on success returns 0 otherwise nonzero error number.
145 : */
146 : int frr_pthread_set_name(struct frr_pthread *fpt);
147 :
148 : /*
149 : * Destroys an frr_pthread.
150 : *
151 : * Assumes that the associated pthread, if any, has already terminated.
152 : *
153 : * @param fpt - the frr_pthread to destroy
154 : */
155 : void frr_pthread_destroy(struct frr_pthread *fpt);
156 :
157 : /*
158 : * Creates a new pthread and binds it to a frr_pthread.
159 : *
160 : * This function is a wrapper for pthread_create. The first parameter is the
161 : * frr_pthread to bind the created pthread to. All subsequent arguments are
162 : * passed unmodified to pthread_create(). The frr_pthread * provided will be
163 : * used as the argument to the pthread entry function. If it is necessary to
164 : * pass additional data, the 'data' field in the frr_pthread may be used.
165 : *
166 : * This function returns the same code as pthread_create(). If the value is
167 : * zero, the provided frr_pthread is bound to a running POSIX thread. If the
168 : * value is less than zero, the provided frr_pthread is guaranteed to be a
169 : * clean instance that may be susbsequently passed to frr_pthread_run().
170 : *
171 : * @param fpt - frr_pthread * to run
172 : * @param attr - see pthread_create(3)
173 : *
174 : * @return see pthread_create(3)
175 : */
176 : int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr);
177 :
178 : /*
179 : * Waits until the specified pthread has finished setting up and is ready to
180 : * begin work.
181 : *
182 : * If the pthread's code makes use of the startup synchronization mechanism,
183 : * this function should be called before attempting to use the functionality
184 : * exposed by the pthread. It waits until the 'running' condition is satisfied
185 : * (see struct definition of frr_pthread).
186 : *
187 : * @param fpt - the frr_pthread * to wait on
188 : */
189 : void frr_pthread_wait_running(struct frr_pthread *fpt);
190 :
191 : /*
192 : * Notifies other pthreads that the calling thread has finished setting up and
193 : * is ready to begin work.
194 : *
195 : * This will allow any other pthreads waiting in 'frr_pthread_wait_running' to
196 : * proceed.
197 : *
198 : * @param fpt - the frr_pthread * that has finished setting up
199 : */
200 : void frr_pthread_notify_running(struct frr_pthread *fpt);
201 :
202 : /*
203 : * Stops a frr_pthread with a result.
204 : *
205 : * @param fpt - frr_pthread * to stop
206 : * @param result - where to store the thread's result, if any. May be NULL if a
207 : * result is not needed.
208 : */
209 : int frr_pthread_stop(struct frr_pthread *fpt, void **result);
210 :
211 : /* Stops all frr_pthread's. */
212 : void frr_pthread_stop_all(void);
213 :
214 : #ifndef HAVE_PTHREAD_CONDATTR_SETCLOCK
215 : #define pthread_condattr_setclock(A, B)
216 : #endif
217 :
218 : /* mutex auto-lock/unlock */
219 :
220 : /* variant 1:
221 : * (for short blocks, multiple mutexes supported)
222 : * break & return can be used for aborting the block
223 : *
224 : * frr_with_mutex(&mtx, &mtx2) {
225 : * if (error)
226 : * break;
227 : * ...
228 : * }
229 : */
230 : #define _frr_with_mutex(mutex) \
231 : *NAMECTR(_mtx_) __attribute__(( \
232 : unused, cleanup(_frr_mtx_unlock))) = _frr_mtx_lock(mutex), \
233 : /* end */
234 :
235 : #define frr_with_mutex(...) \
236 : for (pthread_mutex_t MACRO_REPEAT(_frr_with_mutex, ##__VA_ARGS__) \
237 : *_once = NULL; _once == NULL; _once = (void *)1) \
238 : /* end */
239 :
240 : /* variant 2:
241 : * (more suitable for long blocks, no extra indentation)
242 : *
243 : * frr_mutex_lock_autounlock(&mtx);
244 : * ...
245 : */
246 : #define frr_mutex_lock_autounlock(mutex) \
247 : pthread_mutex_t *NAMECTR(_mtx_) \
248 : __attribute__((unused, cleanup(_frr_mtx_unlock))) = \
249 : _frr_mtx_lock(mutex) \
250 : /* end */
251 :
252 8853 : static inline pthread_mutex_t *_frr_mtx_lock(pthread_mutex_t *mutex)
253 : {
254 8506 : pthread_mutex_lock(mutex);
255 8818 : return mutex;
256 : }
257 :
258 8869 : static inline void _frr_mtx_unlock(pthread_mutex_t **mutex)
259 : {
260 8805 : if (!*mutex)
261 : return;
262 8567 : pthread_mutex_unlock(*mutex);
263 5004 : *mutex = NULL;
264 : }
265 :
266 : #ifdef __cplusplus
267 : }
268 : #endif
269 :
270 : #endif /* _FRR_PTHREAD_H */
|