Coverage Report

Created: 2025-08-03 06:36

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