Line data Source code
1 : /* Thread management routine header.
2 : * Copyright (C) 1998 Kunihiro Ishiguro
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #ifndef _ZEBRA_THREAD_H
22 : #define _ZEBRA_THREAD_H
23 :
24 : #include <zebra.h>
25 : #include <pthread.h>
26 : #include <poll.h>
27 : #include "monotime.h"
28 : #include "frratomic.h"
29 : #include "typesafe.h"
30 : #include "xref.h"
31 :
32 : #ifdef __cplusplus
33 : extern "C" {
34 : #endif
35 :
36 : extern bool cputime_enabled;
37 : extern unsigned long cputime_threshold;
38 : /* capturing wallclock time is always enabled since it is fast (reading
39 : * hardware TSC w/o syscalls)
40 : */
41 : extern unsigned long walltime_threshold;
42 :
43 : struct rusage_t {
44 : #ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
45 : struct timespec cpu;
46 : #else
47 : struct rusage cpu;
48 : #endif
49 : struct timeval real;
50 : };
51 : #define RUSAGE_T struct rusage_t
52 :
53 : #define GETRUSAGE(X) thread_getrusage(X)
54 :
55 : PREDECL_LIST(thread_list);
56 : PREDECL_HEAP(thread_timer_list);
57 :
58 : struct fd_handler {
59 : /* number of pfd that fit in the allocated space of pfds. This is a
60 : * constant and is the same for both pfds and copy.
61 : */
62 : nfds_t pfdsize;
63 :
64 : /* file descriptors to monitor for i/o */
65 : struct pollfd *pfds;
66 : /* number of pollfds stored in pfds */
67 : nfds_t pfdcount;
68 :
69 : /* chunk used for temp copy of pollfds */
70 : struct pollfd *copy;
71 : /* number of pollfds stored in copy */
72 : nfds_t copycount;
73 : };
74 :
75 : struct xref_threadsched {
76 : struct xref xref;
77 :
78 : const char *funcname;
79 : const char *dest;
80 : uint32_t thread_type;
81 : };
82 :
83 : /* Master of the theads. */
84 : struct thread_master {
85 : char *name;
86 :
87 : struct thread **read;
88 : struct thread **write;
89 : struct thread_timer_list_head timer;
90 : struct thread_list_head event, ready, unuse;
91 : struct list *cancel_req;
92 : bool canceled;
93 : pthread_cond_t cancel_cond;
94 : struct hash *cpu_record;
95 : int io_pipe[2];
96 : int fd_limit;
97 : struct fd_handler handler;
98 : unsigned long alloc;
99 : long selectpoll_timeout;
100 : bool spin;
101 : bool handle_signals;
102 : pthread_mutex_t mtx;
103 : pthread_t owner;
104 :
105 : bool ready_run_loop;
106 : RUSAGE_T last_getrusage;
107 : };
108 :
109 : /* Thread itself. */
110 : struct thread {
111 : uint8_t type; /* thread type */
112 : uint8_t add_type; /* thread type */
113 : struct thread_list_item threaditem;
114 : struct thread_timer_list_item timeritem;
115 : struct thread **ref; /* external reference (if given) */
116 : struct thread_master *master; /* pointer to the struct thread_master */
117 : void (*func)(struct thread *); /* event function */
118 : void *arg; /* event argument */
119 : union {
120 : int val; /* second argument of the event. */
121 : int fd; /* file descriptor in case of r/w */
122 : struct timeval sands; /* rest of time sands value. */
123 : } u;
124 : struct timeval real;
125 : struct cpu_thread_history *hist; /* cache pointer to cpu_history */
126 : unsigned long yield; /* yield time in microseconds */
127 : const struct xref_threadsched *xref; /* origin location */
128 : pthread_mutex_t mtx; /* mutex for thread.c functions */
129 : bool ignore_timer_late;
130 : };
131 :
132 : #ifdef _FRR_ATTRIBUTE_PRINTFRR
133 : #pragma FRR printfrr_ext "%pTH" (struct thread *)
134 : #endif
135 :
136 : struct cpu_thread_history {
137 : void (*func)(struct thread *);
138 : atomic_size_t total_cpu_warn;
139 : atomic_size_t total_wall_warn;
140 : atomic_size_t total_starv_warn;
141 : atomic_size_t total_calls;
142 : atomic_size_t total_active;
143 : struct time_stats {
144 : atomic_size_t total, max;
145 : } real;
146 : struct time_stats cpu;
147 : atomic_uint_fast32_t types;
148 : const char *funcname;
149 : };
150 :
151 : /* Struct timeval's tv_usec one second value. */
152 : #define TIMER_SECOND_MICRO 1000000L
153 :
154 : /* Thread types. */
155 : #define THREAD_READ 0
156 : #define THREAD_WRITE 1
157 : #define THREAD_TIMER 2
158 : #define THREAD_EVENT 3
159 : #define THREAD_READY 4
160 : #define THREAD_UNUSED 5
161 : #define THREAD_EXECUTE 6
162 :
163 : /* Thread yield time. */
164 : #define THREAD_YIELD_TIME_SLOT 10 * 1000L /* 10ms */
165 :
166 : #define THREAD_TIMER_STRLEN 12
167 :
168 : /* Macros. */
169 : #define THREAD_ARG(X) ((X)->arg)
170 : #define THREAD_FD(X) ((X)->u.fd)
171 : #define THREAD_VAL(X) ((X)->u.val)
172 :
173 : /*
174 : * Please consider this macro deprecated, and do not use it in new code.
175 : */
176 : #define THREAD_OFF(thread) \
177 : do { \
178 : if ((thread)) \
179 : thread_cancel(&(thread)); \
180 : } while (0)
181 :
182 : /*
183 : * Macro wrappers to generate xrefs for all thread add calls. Includes
184 : * file/line/function info for debugging/tracing.
185 : */
186 : #include "lib/xref.h"
187 :
188 : #define _xref_t_a(addfn, type, m, f, a, v, t) \
189 : ({ \
190 : static const struct xref_threadsched _xref \
191 : __attribute__((used)) = { \
192 : .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__), \
193 : .funcname = #f, \
194 : .dest = #t, \
195 : .thread_type = THREAD_ ## type, \
196 : }; \
197 : XREF_LINK(_xref.xref); \
198 : _thread_add_ ## addfn(&_xref, m, f, a, v, t); \
199 : }) \
200 : /* end */
201 :
202 : #define thread_add_read(m,f,a,v,t) _xref_t_a(read_write, READ, m,f,a,v,t)
203 : #define thread_add_write(m,f,a,v,t) _xref_t_a(read_write, WRITE, m,f,a,v,t)
204 : #define thread_add_timer(m,f,a,v,t) _xref_t_a(timer, TIMER, m,f,a,v,t)
205 : #define thread_add_timer_msec(m,f,a,v,t) _xref_t_a(timer_msec, TIMER, m,f,a,v,t)
206 : #define thread_add_timer_tv(m,f,a,v,t) _xref_t_a(timer_tv, TIMER, m,f,a,v,t)
207 : #define thread_add_event(m,f,a,v,t) _xref_t_a(event, EVENT, m,f,a,v,t)
208 :
209 : #define thread_execute(m,f,a,v) \
210 : ({ \
211 : static const struct xref_threadsched _xref \
212 : __attribute__((used)) = { \
213 : .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__), \
214 : .funcname = #f, \
215 : .dest = NULL, \
216 : .thread_type = THREAD_EXECUTE, \
217 : }; \
218 : XREF_LINK(_xref.xref); \
219 : _thread_execute(&_xref, m, f, a, v); \
220 : }) /* end */
221 :
222 : /* Prototypes. */
223 : extern struct thread_master *thread_master_create(const char *);
224 : void thread_master_set_name(struct thread_master *master, const char *name);
225 : extern void thread_master_free(struct thread_master *);
226 : extern void thread_master_free_unused(struct thread_master *);
227 :
228 : extern void _thread_add_read_write(const struct xref_threadsched *xref,
229 : struct thread_master *master,
230 : void (*fn)(struct thread *), void *arg,
231 : int fd, struct thread **tref);
232 :
233 : extern void _thread_add_timer(const struct xref_threadsched *xref,
234 : struct thread_master *master,
235 : void (*fn)(struct thread *), void *arg, long t,
236 : struct thread **tref);
237 :
238 : extern void _thread_add_timer_msec(const struct xref_threadsched *xref,
239 : struct thread_master *master,
240 : void (*fn)(struct thread *), void *arg,
241 : long t, struct thread **tref);
242 :
243 : extern void _thread_add_timer_tv(const struct xref_threadsched *xref,
244 : struct thread_master *master,
245 : void (*fn)(struct thread *), void *arg,
246 : struct timeval *tv, struct thread **tref);
247 :
248 : extern void _thread_add_event(const struct xref_threadsched *xref,
249 : struct thread_master *master,
250 : void (*fn)(struct thread *), void *arg, int val,
251 : struct thread **tref);
252 :
253 : extern void _thread_execute(const struct xref_threadsched *xref,
254 : struct thread_master *master,
255 : void (*fn)(struct thread *), void *arg, int val);
256 :
257 : extern void thread_cancel(struct thread **event);
258 : extern void thread_cancel_async(struct thread_master *, struct thread **,
259 : void *);
260 : /* Cancel ready tasks with an arg matching 'arg' */
261 : extern void thread_cancel_event_ready(struct thread_master *m, void *arg);
262 : /* Cancel all tasks with an arg matching 'arg', including timers and io */
263 : extern void thread_cancel_event(struct thread_master *m, void *arg);
264 : extern struct thread *thread_fetch(struct thread_master *, struct thread *);
265 : extern void thread_call(struct thread *);
266 : extern unsigned long thread_timer_remain_second(struct thread *);
267 : extern struct timeval thread_timer_remain(struct thread *);
268 : extern unsigned long thread_timer_remain_msec(struct thread *);
269 : extern int thread_should_yield(struct thread *);
270 : /* set yield time for thread */
271 : extern void thread_set_yield_time(struct thread *, unsigned long);
272 :
273 : /* Internal libfrr exports */
274 : extern void thread_getrusage(RUSAGE_T *);
275 : extern void thread_cmd_init(void);
276 :
277 : /* Returns elapsed real (wall clock) time. */
278 : extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
279 : unsigned long *cpu_time_elapsed);
280 :
281 : /* only for use in logging functions! */
282 : extern pthread_key_t thread_current;
283 : extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
284 : struct thread *t_timer);
285 :
286 227 : static inline bool thread_is_scheduled(struct thread *thread)
287 : {
288 227 : if (thread)
289 36 : return true;
290 :
291 : return false;
292 : }
293 :
294 : /* Debug signal mask */
295 : void debug_signals(const sigset_t *sigs);
296 :
297 41 : static inline void thread_ignore_late_timer(struct thread *thread)
298 : {
299 41 : thread->ignore_timer_late = true;
300 27 : }
301 :
302 : #ifdef __cplusplus
303 : }
304 : #endif
305 :
306 : #endif /* _ZEBRA_THREAD_H */
|