]> git.proxmox.com Git - mirror_frr.git/blame - lib/thread.c
lib/xref: work around GCC bug 41091
[mirror_frr.git] / lib / thread.c
CommitLineData
718e3744 1/* Thread management routine
2 * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
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 *
896014f4
DL
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
718e3744 19 */
20
21/* #define DEBUG */
22
23#include <zebra.h>
308d14ae 24#include <sys/resource.h>
718e3744 25
26#include "thread.h"
27#include "memory.h"
3e41733f 28#include "frrcu.h"
718e3744 29#include "log.h"
e04ab74d 30#include "hash.h"
31#include "command.h"
05c447dd 32#include "sigevent.h"
3bf2673b 33#include "network.h"
bd74dc61 34#include "jhash.h"
fbcac826 35#include "frratomic.h"
00dffa8c 36#include "frr_pthread.h"
9ef9495e 37#include "lib_errors.h"
912d45a1 38#include "libfrr_trace.h"
1a9f340b 39#include "libfrr.h"
d6be5fb9 40
d62a17ae 41DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
4a1ab8e4 42DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
a6f235f3 43DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info")
d62a17ae 44DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
4a1ab8e4 45
c284542b
DL
46DECLARE_LIST(thread_list, struct thread, threaditem)
47
27d29ced
DL
48static int thread_timer_cmp(const struct thread *a, const struct thread *b)
49{
50 if (a->u.sands.tv_sec < b->u.sands.tv_sec)
51 return -1;
52 if (a->u.sands.tv_sec > b->u.sands.tv_sec)
53 return 1;
54 if (a->u.sands.tv_usec < b->u.sands.tv_usec)
55 return -1;
56 if (a->u.sands.tv_usec > b->u.sands.tv_usec)
57 return 1;
58 return 0;
59}
60
61DECLARE_HEAP(thread_timer_list, struct thread, timeritem,
62 thread_timer_cmp)
63
3b96b781
HT
64#if defined(__APPLE__)
65#include <mach/mach.h>
66#include <mach/mach_time.h>
67#endif
68
d62a17ae 69#define AWAKEN(m) \
70 do { \
2b64873d 71 const unsigned char wakebyte = 0x01; \
d62a17ae 72 write(m->io_pipe[1], &wakebyte, 1); \
73 } while (0);
3bf2673b 74
62f44022 75/* control variable for initializer */
c17faa4b 76static pthread_once_t init_once = PTHREAD_ONCE_INIT;
e0bebc7c 77pthread_key_t thread_current;
6b0655a2 78
c17faa4b 79static pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
62f44022
QY
80static struct list *masters;
81
6655966d 82static void thread_free(struct thread_master *master, struct thread *thread);
6b0655a2 83
62f44022 84/* CLI start ---------------------------------------------------------------- */
d8b87afe 85static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
e04ab74d 86{
883cc51d 87 int size = sizeof(a->func);
bd74dc61
DS
88
89 return jhash(&a->func, size, 0);
e04ab74d 90}
91
74df8d6d 92static bool cpu_record_hash_cmp(const struct cpu_thread_history *a,
d62a17ae 93 const struct cpu_thread_history *b)
e04ab74d 94{
d62a17ae 95 return a->func == b->func;
e04ab74d 96}
97
d62a17ae 98static void *cpu_record_hash_alloc(struct cpu_thread_history *a)
e04ab74d 99{
d62a17ae 100 struct cpu_thread_history *new;
101 new = XCALLOC(MTYPE_THREAD_STATS, sizeof(struct cpu_thread_history));
102 new->func = a->func;
103 new->funcname = a->funcname;
104 return new;
e04ab74d 105}
106
d62a17ae 107static void cpu_record_hash_free(void *a)
228da428 108{
d62a17ae 109 struct cpu_thread_history *hist = a;
110
111 XFREE(MTYPE_THREAD_STATS, hist);
228da428
CC
112}
113
f75e802d 114#ifndef EXCLUDE_CPU_TIME
d62a17ae 115static void vty_out_cpu_thread_history(struct vty *vty,
116 struct cpu_thread_history *a)
e04ab74d 117{
9a8a7b0e 118 vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
72327cf3
MS
119 a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
120 a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
121 (a->real.total / a->total_calls), a->real.max);
84d951d0 122 vty_out(vty, " %c%c%c%c%c %s\n",
d62a17ae 123 a->types & (1 << THREAD_READ) ? 'R' : ' ',
124 a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
125 a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
126 a->types & (1 << THREAD_EVENT) ? 'E' : ' ',
127 a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname);
e04ab74d 128}
129
e3b78da8 130static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[])
e04ab74d 131{
d62a17ae 132 struct cpu_thread_history *totals = args[0];
fbcac826 133 struct cpu_thread_history copy;
d62a17ae 134 struct vty *vty = args[1];
fbcac826 135 uint8_t *filter = args[2];
d62a17ae 136
137 struct cpu_thread_history *a = bucket->data;
138
fbcac826
QY
139 copy.total_active =
140 atomic_load_explicit(&a->total_active, memory_order_seq_cst);
141 copy.total_calls =
142 atomic_load_explicit(&a->total_calls, memory_order_seq_cst);
143 copy.cpu.total =
144 atomic_load_explicit(&a->cpu.total, memory_order_seq_cst);
145 copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst);
146 copy.real.total =
147 atomic_load_explicit(&a->real.total, memory_order_seq_cst);
148 copy.real.max =
149 atomic_load_explicit(&a->real.max, memory_order_seq_cst);
150 copy.types = atomic_load_explicit(&a->types, memory_order_seq_cst);
151 copy.funcname = a->funcname;
152
153 if (!(copy.types & *filter))
d62a17ae 154 return;
fbcac826
QY
155
156 vty_out_cpu_thread_history(vty, &copy);
157 totals->total_active += copy.total_active;
158 totals->total_calls += copy.total_calls;
159 totals->real.total += copy.real.total;
160 if (totals->real.max < copy.real.max)
161 totals->real.max = copy.real.max;
162 totals->cpu.total += copy.cpu.total;
163 if (totals->cpu.max < copy.cpu.max)
164 totals->cpu.max = copy.cpu.max;
e04ab74d 165}
166
fbcac826 167static void cpu_record_print(struct vty *vty, uint8_t filter)
e04ab74d 168{
d62a17ae 169 struct cpu_thread_history tmp;
170 void *args[3] = {&tmp, vty, &filter};
171 struct thread_master *m;
172 struct listnode *ln;
173
0d6f7fd6 174 memset(&tmp, 0, sizeof(tmp));
d62a17ae 175 tmp.funcname = "TOTAL";
176 tmp.types = filter;
177
00dffa8c 178 frr_with_mutex(&masters_mtx) {
d62a17ae 179 for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
180 const char *name = m->name ? m->name : "main";
181
182 char underline[strlen(name) + 1];
183 memset(underline, '-', sizeof(underline));
4f113d60 184 underline[sizeof(underline) - 1] = '\0';
d62a17ae 185
186 vty_out(vty, "\n");
187 vty_out(vty, "Showing statistics for pthread %s\n",
188 name);
189 vty_out(vty, "-------------------------------%s\n",
190 underline);
84d951d0 191 vty_out(vty, "%30s %18s %18s\n", "",
d62a17ae 192 "CPU (user+system):", "Real (wall-clock):");
193 vty_out(vty,
194 "Active Runtime(ms) Invoked Avg uSec Max uSecs");
195 vty_out(vty, " Avg uSec Max uSecs");
196 vty_out(vty, " Type Thread\n");
197
198 if (m->cpu_record->count)
199 hash_iterate(
200 m->cpu_record,
e3b78da8 201 (void (*)(struct hash_bucket *,
d62a17ae 202 void *))cpu_record_hash_print,
203 args);
204 else
205 vty_out(vty, "No data to display yet.\n");
206
207 vty_out(vty, "\n");
208 }
209 }
d62a17ae 210
211 vty_out(vty, "\n");
212 vty_out(vty, "Total thread statistics\n");
213 vty_out(vty, "-------------------------\n");
84d951d0 214 vty_out(vty, "%30s %18s %18s\n", "",
d62a17ae 215 "CPU (user+system):", "Real (wall-clock):");
216 vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
217 vty_out(vty, " Avg uSec Max uSecs");
218 vty_out(vty, " Type Thread\n");
219
220 if (tmp.total_calls > 0)
221 vty_out_cpu_thread_history(vty, &tmp);
e04ab74d 222}
f75e802d 223#endif
e04ab74d 224
e3b78da8 225static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[])
e276eb82 226{
fbcac826 227 uint8_t *filter = args[0];
d62a17ae 228 struct hash *cpu_record = args[1];
229
230 struct cpu_thread_history *a = bucket->data;
62f44022 231
d62a17ae 232 if (!(a->types & *filter))
233 return;
f48f65d2 234
d62a17ae 235 hash_release(cpu_record, bucket->data);
e276eb82
PJ
236}
237
fbcac826 238static void cpu_record_clear(uint8_t filter)
e276eb82 239{
fbcac826 240 uint8_t *tmp = &filter;
d62a17ae 241 struct thread_master *m;
242 struct listnode *ln;
243
00dffa8c 244 frr_with_mutex(&masters_mtx) {
d62a17ae 245 for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
00dffa8c 246 frr_with_mutex(&m->mtx) {
d62a17ae 247 void *args[2] = {tmp, m->cpu_record};
248 hash_iterate(
249 m->cpu_record,
e3b78da8 250 (void (*)(struct hash_bucket *,
d62a17ae 251 void *))cpu_record_hash_clear,
252 args);
253 }
d62a17ae 254 }
255 }
62f44022
QY
256}
257
fbcac826 258static uint8_t parse_filter(const char *filterstr)
62f44022 259{
d62a17ae 260 int i = 0;
261 int filter = 0;
262
263 while (filterstr[i] != '\0') {
264 switch (filterstr[i]) {
265 case 'r':
266 case 'R':
267 filter |= (1 << THREAD_READ);
268 break;
269 case 'w':
270 case 'W':
271 filter |= (1 << THREAD_WRITE);
272 break;
273 case 't':
274 case 'T':
275 filter |= (1 << THREAD_TIMER);
276 break;
277 case 'e':
278 case 'E':
279 filter |= (1 << THREAD_EVENT);
280 break;
281 case 'x':
282 case 'X':
283 filter |= (1 << THREAD_EXECUTE);
284 break;
285 default:
286 break;
287 }
288 ++i;
289 }
290 return filter;
62f44022
QY
291}
292
f75e802d 293#ifndef EXCLUDE_CPU_TIME
62f44022
QY
294DEFUN (show_thread_cpu,
295 show_thread_cpu_cmd,
296 "show thread cpu [FILTER]",
297 SHOW_STR
298 "Thread information\n"
299 "Thread CPU usage\n"
61fa0b97 300 "Display filter (rwtex)\n")
62f44022 301{
fbcac826 302 uint8_t filter = (uint8_t)-1U;
d62a17ae 303 int idx = 0;
304
305 if (argv_find(argv, argc, "FILTER", &idx)) {
306 filter = parse_filter(argv[idx]->arg);
307 if (!filter) {
308 vty_out(vty,
3efd0893 309 "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
d62a17ae 310 argv[idx]->arg);
311 return CMD_WARNING;
312 }
313 }
314
315 cpu_record_print(vty, filter);
316 return CMD_SUCCESS;
e276eb82 317}
f75e802d 318#endif
e276eb82 319
8872626b
DS
320static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
321{
322 const char *name = m->name ? m->name : "main";
323 char underline[strlen(name) + 1];
a0b36ae6 324 struct thread *thread;
8872626b
DS
325 uint32_t i;
326
327 memset(underline, '-', sizeof(underline));
328 underline[sizeof(underline) - 1] = '\0';
329
330 vty_out(vty, "\nShowing poll FD's for %s\n", name);
331 vty_out(vty, "----------------------%s\n", underline);
6c19478a
DS
332 vty_out(vty, "Count: %u/%d\n", (uint32_t)m->handler.pfdcount,
333 m->fd_limit);
a0b36ae6
DS
334 for (i = 0; i < m->handler.pfdcount; i++) {
335 vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\t\t", i,
336 m->handler.pfds[i].fd, m->handler.pfds[i].events,
8872626b 337 m->handler.pfds[i].revents);
a0b36ae6
DS
338
339 if (m->handler.pfds[i].events & POLLIN) {
340 thread = m->read[m->handler.pfds[i].fd];
341
342 if (!thread)
343 vty_out(vty, "ERROR ");
344 else
60a3efec 345 vty_out(vty, "%s ", thread->xref->funcname);
a0b36ae6
DS
346 } else
347 vty_out(vty, " ");
348
349 if (m->handler.pfds[i].events & POLLOUT) {
350 thread = m->write[m->handler.pfds[i].fd];
351
352 if (!thread)
353 vty_out(vty, "ERROR\n");
354 else
60a3efec 355 vty_out(vty, "%s\n", thread->xref->funcname);
a0b36ae6
DS
356 } else
357 vty_out(vty, "\n");
358 }
8872626b
DS
359}
360
361DEFUN (show_thread_poll,
362 show_thread_poll_cmd,
363 "show thread poll",
364 SHOW_STR
365 "Thread information\n"
366 "Show poll FD's and information\n")
367{
368 struct listnode *node;
369 struct thread_master *m;
370
00dffa8c 371 frr_with_mutex(&masters_mtx) {
8872626b
DS
372 for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
373 show_thread_poll_helper(vty, m);
374 }
375 }
8872626b
DS
376
377 return CMD_SUCCESS;
378}
379
380
49d41a26
DS
381DEFUN (clear_thread_cpu,
382 clear_thread_cpu_cmd,
383 "clear thread cpu [FILTER]",
62f44022 384 "Clear stored data in all pthreads\n"
49d41a26
DS
385 "Thread information\n"
386 "Thread CPU usage\n"
387 "Display filter (rwtexb)\n")
e276eb82 388{
fbcac826 389 uint8_t filter = (uint8_t)-1U;
d62a17ae 390 int idx = 0;
391
392 if (argv_find(argv, argc, "FILTER", &idx)) {
393 filter = parse_filter(argv[idx]->arg);
394 if (!filter) {
395 vty_out(vty,
3efd0893 396 "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
d62a17ae 397 argv[idx]->arg);
398 return CMD_WARNING;
399 }
400 }
401
402 cpu_record_clear(filter);
403 return CMD_SUCCESS;
e276eb82 404}
6b0655a2 405
d62a17ae 406void thread_cmd_init(void)
0b84f294 407{
f75e802d 408#ifndef EXCLUDE_CPU_TIME
d62a17ae 409 install_element(VIEW_NODE, &show_thread_cpu_cmd);
f75e802d 410#endif
8872626b 411 install_element(VIEW_NODE, &show_thread_poll_cmd);
d62a17ae 412 install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
0b84f294 413}
62f44022
QY
414/* CLI end ------------------------------------------------------------------ */
415
0b84f294 416
d62a17ae 417static void cancelreq_del(void *cr)
63ccb9cb 418{
d62a17ae 419 XFREE(MTYPE_TMP, cr);
63ccb9cb
QY
420}
421
e0bebc7c 422/* initializer, only ever called once */
4d762f26 423static void initializer(void)
e0bebc7c 424{
d62a17ae 425 pthread_key_create(&thread_current, NULL);
e0bebc7c
QY
426}
427
d62a17ae 428struct thread_master *thread_master_create(const char *name)
718e3744 429{
d62a17ae 430 struct thread_master *rv;
431 struct rlimit limit;
432
433 pthread_once(&init_once, &initializer);
434
435 rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
d62a17ae 436
437 /* Initialize master mutex */
438 pthread_mutex_init(&rv->mtx, NULL);
439 pthread_cond_init(&rv->cancel_cond, NULL);
440
441 /* Set name */
7ffcd8bd
QY
442 name = name ? name : "default";
443 rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
d62a17ae 444
445 /* Initialize I/O task data structures */
1a9f340b
MS
446
447 /* Use configured limit if present, ulimit otherwise. */
448 rv->fd_limit = frr_get_fd_limit();
449 if (rv->fd_limit == 0) {
450 getrlimit(RLIMIT_NOFILE, &limit);
451 rv->fd_limit = (int)limit.rlim_cur;
452 }
453
a6f235f3
DS
454 rv->read = XCALLOC(MTYPE_THREAD_POLL,
455 sizeof(struct thread *) * rv->fd_limit);
456
457 rv->write = XCALLOC(MTYPE_THREAD_POLL,
458 sizeof(struct thread *) * rv->fd_limit);
d62a17ae 459
7ffcd8bd
QY
460 char tmhashname[strlen(name) + 32];
461 snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash",
462 name);
bd74dc61 463 rv->cpu_record = hash_create_size(
d8b87afe 464 8, (unsigned int (*)(const void *))cpu_record_hash_key,
74df8d6d 465 (bool (*)(const void *, const void *))cpu_record_hash_cmp,
7ffcd8bd 466 tmhashname);
d62a17ae 467
c284542b
DL
468 thread_list_init(&rv->event);
469 thread_list_init(&rv->ready);
470 thread_list_init(&rv->unuse);
27d29ced 471 thread_timer_list_init(&rv->timer);
d62a17ae 472
473 /* Initialize thread_fetch() settings */
474 rv->spin = true;
475 rv->handle_signals = true;
476
477 /* Set pthread owner, should be updated by actual owner */
478 rv->owner = pthread_self();
479 rv->cancel_req = list_new();
480 rv->cancel_req->del = cancelreq_del;
481 rv->canceled = true;
482
483 /* Initialize pipe poker */
484 pipe(rv->io_pipe);
485 set_nonblocking(rv->io_pipe[0]);
486 set_nonblocking(rv->io_pipe[1]);
487
488 /* Initialize data structures for poll() */
489 rv->handler.pfdsize = rv->fd_limit;
490 rv->handler.pfdcount = 0;
491 rv->handler.pfds = XCALLOC(MTYPE_THREAD_MASTER,
492 sizeof(struct pollfd) * rv->handler.pfdsize);
493 rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER,
494 sizeof(struct pollfd) * rv->handler.pfdsize);
495
eff09c66 496 /* add to list of threadmasters */
00dffa8c 497 frr_with_mutex(&masters_mtx) {
eff09c66
QY
498 if (!masters)
499 masters = list_new();
500
d62a17ae 501 listnode_add(masters, rv);
502 }
d62a17ae 503
504 return rv;
718e3744 505}
506
d8a8a8de
QY
507void thread_master_set_name(struct thread_master *master, const char *name)
508{
00dffa8c 509 frr_with_mutex(&master->mtx) {
0a22ddfb 510 XFREE(MTYPE_THREAD_MASTER, master->name);
d8a8a8de
QY
511 master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
512 }
d8a8a8de
QY
513}
514
6ed04aa2
DS
515#define THREAD_UNUSED_DEPTH 10
516
718e3744 517/* Move thread to unuse list. */
d62a17ae 518static void thread_add_unuse(struct thread_master *m, struct thread *thread)
718e3744 519{
6655966d
RZ
520 pthread_mutex_t mtxc = thread->mtx;
521
d62a17ae 522 assert(m != NULL && thread != NULL);
d62a17ae 523
d62a17ae 524 thread->hist->total_active--;
6ed04aa2
DS
525 memset(thread, 0, sizeof(struct thread));
526 thread->type = THREAD_UNUSED;
527
6655966d
RZ
528 /* Restore the thread mutex context. */
529 thread->mtx = mtxc;
530
c284542b
DL
531 if (thread_list_count(&m->unuse) < THREAD_UNUSED_DEPTH) {
532 thread_list_add_tail(&m->unuse, thread);
6655966d
RZ
533 return;
534 }
535
536 thread_free(m, thread);
718e3744 537}
538
539/* Free all unused thread. */
c284542b
DL
540static void thread_list_free(struct thread_master *m,
541 struct thread_list_head *list)
718e3744 542{
d62a17ae 543 struct thread *t;
d62a17ae 544
c284542b 545 while ((t = thread_list_pop(list)))
6655966d 546 thread_free(m, t);
718e3744 547}
548
d62a17ae 549static void thread_array_free(struct thread_master *m,
550 struct thread **thread_array)
308d14ae 551{
d62a17ae 552 struct thread *t;
553 int index;
554
555 for (index = 0; index < m->fd_limit; ++index) {
556 t = thread_array[index];
557 if (t) {
558 thread_array[index] = NULL;
6655966d 559 thread_free(m, t);
d62a17ae 560 }
561 }
a6f235f3 562 XFREE(MTYPE_THREAD_POLL, thread_array);
308d14ae
DV
563}
564
495f0b13
DS
565/*
566 * thread_master_free_unused
567 *
568 * As threads are finished with they are put on the
569 * unuse list for later reuse.
570 * If we are shutting down, Free up unused threads
571 * So we can see if we forget to shut anything off
572 */
d62a17ae 573void thread_master_free_unused(struct thread_master *m)
495f0b13 574{
00dffa8c 575 frr_with_mutex(&m->mtx) {
d62a17ae 576 struct thread *t;
c284542b 577 while ((t = thread_list_pop(&m->unuse)))
6655966d 578 thread_free(m, t);
d62a17ae 579 }
495f0b13
DS
580}
581
718e3744 582/* Stop thread scheduler. */
d62a17ae 583void thread_master_free(struct thread_master *m)
718e3744 584{
27d29ced
DL
585 struct thread *t;
586
00dffa8c 587 frr_with_mutex(&masters_mtx) {
d62a17ae 588 listnode_delete(masters, m);
eff09c66 589 if (masters->count == 0) {
6a154c88 590 list_delete(&masters);
eff09c66 591 }
d62a17ae 592 }
d62a17ae 593
594 thread_array_free(m, m->read);
595 thread_array_free(m, m->write);
27d29ced
DL
596 while ((t = thread_timer_list_pop(&m->timer)))
597 thread_free(m, t);
d62a17ae 598 thread_list_free(m, &m->event);
599 thread_list_free(m, &m->ready);
600 thread_list_free(m, &m->unuse);
601 pthread_mutex_destroy(&m->mtx);
33844bbe 602 pthread_cond_destroy(&m->cancel_cond);
d62a17ae 603 close(m->io_pipe[0]);
604 close(m->io_pipe[1]);
6a154c88 605 list_delete(&m->cancel_req);
1a0a92ea 606 m->cancel_req = NULL;
d62a17ae 607
608 hash_clean(m->cpu_record, cpu_record_hash_free);
609 hash_free(m->cpu_record);
610 m->cpu_record = NULL;
611
0a22ddfb 612 XFREE(MTYPE_THREAD_MASTER, m->name);
d62a17ae 613 XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
614 XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
615 XFREE(MTYPE_THREAD_MASTER, m);
718e3744 616}
617
78ca0342
CF
618/* Return remain time in miliseconds. */
619unsigned long thread_timer_remain_msec(struct thread *thread)
718e3744 620{
d62a17ae 621 int64_t remain;
1189d95f 622
00dffa8c 623 frr_with_mutex(&thread->mtx) {
78ca0342 624 remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
d62a17ae 625 }
1189d95f 626
d62a17ae 627 return remain < 0 ? 0 : remain;
718e3744 628}
629
78ca0342
CF
630/* Return remain time in seconds. */
631unsigned long thread_timer_remain_second(struct thread *thread)
632{
633 return thread_timer_remain_msec(thread) / 1000LL;
634}
635
9c7753e4
DL
636#define debugargdef const char *funcname, const char *schedfrom, int fromln
637#define debugargpass funcname, schedfrom, fromln
e04ab74d 638
d62a17ae 639struct timeval thread_timer_remain(struct thread *thread)
6ac44687 640{
d62a17ae 641 struct timeval remain;
00dffa8c 642 frr_with_mutex(&thread->mtx) {
d62a17ae 643 monotime_until(&thread->u.sands, &remain);
644 }
d62a17ae 645 return remain;
6ac44687
CF
646}
647
0447957e
AK
648static int time_hhmmss(char *buf, int buf_size, long sec)
649{
650 long hh;
651 long mm;
652 int wr;
653
654 zassert(buf_size >= 8);
655
656 hh = sec / 3600;
657 sec %= 3600;
658 mm = sec / 60;
659 sec %= 60;
660
661 wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec);
662
663 return wr != 8;
664}
665
666char *thread_timer_to_hhmmss(char *buf, int buf_size,
667 struct thread *t_timer)
668{
669 if (t_timer) {
670 time_hhmmss(buf, buf_size,
671 thread_timer_remain_second(t_timer));
672 } else {
673 snprintf(buf, buf_size, "--:--:--");
674 }
675 return buf;
676}
677
718e3744 678/* Get new thread. */
d7c0a89a 679static struct thread *thread_get(struct thread_master *m, uint8_t type,
d62a17ae 680 int (*func)(struct thread *), void *arg,
60a3efec 681 const struct xref_threadsched *xref)
718e3744 682{
c284542b 683 struct thread *thread = thread_list_pop(&m->unuse);
d62a17ae 684 struct cpu_thread_history tmp;
685
686 if (!thread) {
687 thread = XCALLOC(MTYPE_THREAD, sizeof(struct thread));
688 /* mutex only needs to be initialized at struct creation. */
689 pthread_mutex_init(&thread->mtx, NULL);
690 m->alloc++;
691 }
692
693 thread->type = type;
694 thread->add_type = type;
695 thread->master = m;
696 thread->arg = arg;
d62a17ae 697 thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
698 thread->ref = NULL;
699
700 /*
701 * So if the passed in funcname is not what we have
702 * stored that means the thread->hist needs to be
703 * updated. We keep the last one around in unused
704 * under the assumption that we are probably
705 * going to immediately allocate the same
706 * type of thread.
707 * This hopefully saves us some serious
708 * hash_get lookups.
709 */
60a3efec
DL
710 if ((thread->xref && thread->xref->funcname != xref->funcname)
711 || thread->func != func) {
d62a17ae 712 tmp.func = func;
60a3efec 713 tmp.funcname = xref->funcname;
d62a17ae 714 thread->hist =
715 hash_get(m->cpu_record, &tmp,
716 (void *(*)(void *))cpu_record_hash_alloc);
717 }
718 thread->hist->total_active++;
719 thread->func = func;
60a3efec 720 thread->xref = xref;
d62a17ae 721
722 return thread;
718e3744 723}
724
6655966d
RZ
725static void thread_free(struct thread_master *master, struct thread *thread)
726{
727 /* Update statistics. */
728 assert(master->alloc > 0);
729 master->alloc--;
730
731 /* Free allocated resources. */
732 pthread_mutex_destroy(&thread->mtx);
733 XFREE(MTYPE_THREAD, thread);
734}
735
d81ca9a3
MS
736static int fd_poll(struct thread_master *m, const struct timeval *timer_wait,
737 bool *eintr_p)
209a72a6 738{
d81ca9a3
MS
739 sigset_t origsigs;
740 unsigned char trash[64];
741 nfds_t count = m->handler.copycount;
742
d279ef57
DS
743 /*
744 * If timer_wait is null here, that means poll() should block
745 * indefinitely, unless the thread_master has overridden it by setting
d62a17ae 746 * ->selectpoll_timeout.
d279ef57 747 *
d62a17ae 748 * If the value is positive, it specifies the maximum number of
d279ef57
DS
749 * milliseconds to wait. If the timeout is -1, it specifies that
750 * we should never wait and always return immediately even if no
751 * event is detected. If the value is zero, the behavior is default.
752 */
d62a17ae 753 int timeout = -1;
754
755 /* number of file descriptors with events */
756 int num;
757
758 if (timer_wait != NULL
759 && m->selectpoll_timeout == 0) // use the default value
760 timeout = (timer_wait->tv_sec * 1000)
761 + (timer_wait->tv_usec / 1000);
762 else if (m->selectpoll_timeout > 0) // use the user's timeout
763 timeout = m->selectpoll_timeout;
764 else if (m->selectpoll_timeout
765 < 0) // effect a poll (return immediately)
766 timeout = 0;
767
0bdeb5e5 768 zlog_tls_buffer_flush();
3e41733f
DL
769 rcu_read_unlock();
770 rcu_assert_read_unlocked();
771
d62a17ae 772 /* add poll pipe poker */
d81ca9a3
MS
773 assert(count + 1 < m->handler.pfdsize);
774 m->handler.copy[count].fd = m->io_pipe[0];
775 m->handler.copy[count].events = POLLIN;
776 m->handler.copy[count].revents = 0x00;
777
778 /* We need to deal with a signal-handling race here: we
779 * don't want to miss a crucial signal, such as SIGTERM or SIGINT,
780 * that may arrive just before we enter poll(). We will block the
781 * key signals, then check whether any have arrived - if so, we return
782 * before calling poll(). If not, we'll re-enable the signals
783 * in the ppoll() call.
784 */
785
786 sigemptyset(&origsigs);
787 if (m->handle_signals) {
788 /* Main pthread that handles the app signals */
789 if (frr_sigevent_check(&origsigs)) {
790 /* Signal to process - restore signal mask and return */
791 pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
792 num = -1;
793 *eintr_p = true;
794 goto done;
795 }
796 } else {
797 /* Don't make any changes for the non-main pthreads */
798 pthread_sigmask(SIG_SETMASK, NULL, &origsigs);
799 }
d62a17ae 800
d81ca9a3
MS
801#if defined(HAVE_PPOLL)
802 struct timespec ts, *tsp;
803
804 if (timeout >= 0) {
805 ts.tv_sec = timeout / 1000;
806 ts.tv_nsec = (timeout % 1000) * 1000000;
807 tsp = &ts;
808 } else
809 tsp = NULL;
810
811 num = ppoll(m->handler.copy, count + 1, tsp, &origsigs);
812 pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
813#else
814 /* Not ideal - there is a race after we restore the signal mask */
815 pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
816 num = poll(m->handler.copy, count + 1, timeout);
817#endif
d62a17ae 818
d81ca9a3
MS
819done:
820
821 if (num < 0 && errno == EINTR)
822 *eintr_p = true;
823
824 if (num > 0 && m->handler.copy[count].revents != 0 && num--)
d62a17ae 825 while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
826 ;
827
3e41733f
DL
828 rcu_read_lock();
829
d62a17ae 830 return num;
209a72a6
DS
831}
832
718e3744 833/* Add new read thread. */
60a3efec
DL
834struct thread *_thread_add_read_write(const struct xref_threadsched *xref,
835 struct thread_master *m,
836 int (*func)(struct thread *),
837 void *arg, int fd, struct thread **t_ptr)
718e3744 838{
60a3efec 839 int dir = xref->thread_type;
d62a17ae 840 struct thread *thread = NULL;
1ef14bee 841 struct thread **thread_array;
d62a17ae 842
abf96a87 843 if (dir == THREAD_READ)
c7bb4f00
QY
844 frrtrace(9, frr_libfrr, schedule_read, m, funcname, schedfrom,
845 fromln, t_ptr, fd, 0, arg, 0);
abf96a87 846 else
c7bb4f00
QY
847 frrtrace(9, frr_libfrr, schedule_write, m, funcname, schedfrom,
848 fromln, t_ptr, fd, 0, arg, 0);
abf96a87 849
9b864cd3 850 assert(fd >= 0 && fd < m->fd_limit);
00dffa8c
DL
851 frr_with_mutex(&m->mtx) {
852 if (t_ptr && *t_ptr)
853 // thread is already scheduled; don't reschedule
854 break;
d62a17ae 855
856 /* default to a new pollfd */
857 nfds_t queuepos = m->handler.pfdcount;
858
1ef14bee
DS
859 if (dir == THREAD_READ)
860 thread_array = m->read;
861 else
862 thread_array = m->write;
863
d62a17ae 864 /* if we already have a pollfd for our file descriptor, find and
865 * use it */
866 for (nfds_t i = 0; i < m->handler.pfdcount; i++)
867 if (m->handler.pfds[i].fd == fd) {
868 queuepos = i;
1ef14bee
DS
869
870#ifdef DEV_BUILD
871 /*
872 * What happens if we have a thread already
873 * created for this event?
874 */
875 if (thread_array[fd])
876 assert(!"Thread already scheduled for file descriptor");
877#endif
d62a17ae 878 break;
879 }
880
881 /* make sure we have room for this fd + pipe poker fd */
882 assert(queuepos + 1 < m->handler.pfdsize);
883
60a3efec 884 thread = thread_get(m, dir, func, arg, xref);
d62a17ae 885
886 m->handler.pfds[queuepos].fd = fd;
887 m->handler.pfds[queuepos].events |=
888 (dir == THREAD_READ ? POLLIN : POLLOUT);
889
890 if (queuepos == m->handler.pfdcount)
891 m->handler.pfdcount++;
892
893 if (thread) {
00dffa8c 894 frr_with_mutex(&thread->mtx) {
d62a17ae 895 thread->u.fd = fd;
1ef14bee 896 thread_array[thread->u.fd] = thread;
d62a17ae 897 }
d62a17ae 898
899 if (t_ptr) {
900 *t_ptr = thread;
901 thread->ref = t_ptr;
902 }
903 }
904
905 AWAKEN(m);
906 }
d62a17ae 907
908 return thread;
718e3744 909}
910
56a94b36 911static struct thread *
60a3efec
DL
912_thread_add_timer_timeval(const struct xref_threadsched *xref,
913 struct thread_master *m, int (*func)(struct thread *),
914 int type, void *arg, struct timeval *time_relative,
915 struct thread **t_ptr)
718e3744 916{
d62a17ae 917 struct thread *thread;
d62a17ae 918
919 assert(m != NULL);
920
921 assert(type == THREAD_TIMER);
922 assert(time_relative);
923
c7bb4f00
QY
924 frrtrace(9, frr_libfrr, schedule_timer, m, funcname, schedfrom, fromln,
925 t_ptr, 0, 0, arg, (long)time_relative->tv_sec);
abf96a87 926
00dffa8c
DL
927 frr_with_mutex(&m->mtx) {
928 if (t_ptr && *t_ptr)
d279ef57 929 /* thread is already scheduled; don't reschedule */
d62a17ae 930 return NULL;
d62a17ae 931
60a3efec 932 thread = thread_get(m, type, func, arg, xref);
d62a17ae 933
00dffa8c 934 frr_with_mutex(&thread->mtx) {
d62a17ae 935 monotime(&thread->u.sands);
936 timeradd(&thread->u.sands, time_relative,
937 &thread->u.sands);
27d29ced 938 thread_timer_list_add(&m->timer, thread);
d62a17ae 939 if (t_ptr) {
940 *t_ptr = thread;
941 thread->ref = t_ptr;
942 }
943 }
d62a17ae 944
945 AWAKEN(m);
946 }
d62a17ae 947
948 return thread;
9e867fe6 949}
950
98c91ac6 951
952/* Add timer event thread. */
60a3efec
DL
953struct thread *_thread_add_timer(const struct xref_threadsched *xref,
954 struct thread_master *m,
955 int (*func)(struct thread *),
956 void *arg, long timer, struct thread **t_ptr)
9e867fe6 957{
d62a17ae 958 struct timeval trel;
9e867fe6 959
d62a17ae 960 assert(m != NULL);
9e867fe6 961
d62a17ae 962 trel.tv_sec = timer;
963 trel.tv_usec = 0;
9e867fe6 964
60a3efec
DL
965 return _thread_add_timer_timeval(xref, m, func, THREAD_TIMER, arg,
966 &trel, t_ptr);
98c91ac6 967}
9e867fe6 968
98c91ac6 969/* Add timer event thread with "millisecond" resolution */
60a3efec
DL
970struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref,
971 struct thread_master *m,
972 int (*func)(struct thread *),
973 void *arg, long timer,
974 struct thread **t_ptr)
98c91ac6 975{
d62a17ae 976 struct timeval trel;
9e867fe6 977
d62a17ae 978 assert(m != NULL);
718e3744 979
d62a17ae 980 trel.tv_sec = timer / 1000;
981 trel.tv_usec = 1000 * (timer % 1000);
98c91ac6 982
60a3efec
DL
983 return _thread_add_timer_timeval(xref, m, func, THREAD_TIMER, arg,
984 &trel, t_ptr);
a48b4e6d 985}
986
d03c4cbd 987/* Add timer event thread with "millisecond" resolution */
60a3efec
DL
988struct thread *_thread_add_timer_tv(const struct xref_threadsched *xref,
989 struct thread_master *m,
990 int (*func)(struct thread *),
991 void *arg, struct timeval *tv,
992 struct thread **t_ptr)
d03c4cbd 993{
60a3efec
DL
994 return _thread_add_timer_timeval(xref, m, func, THREAD_TIMER, arg, tv,
995 t_ptr);
d03c4cbd
DL
996}
997
718e3744 998/* Add simple event thread. */
60a3efec
DL
999struct thread *_thread_add_event(const struct xref_threadsched *xref,
1000 struct thread_master *m,
1001 int (*func)(struct thread *),
1002 void *arg, int val, struct thread **t_ptr)
718e3744 1003{
00dffa8c 1004 struct thread *thread = NULL;
d62a17ae 1005
c7bb4f00
QY
1006 frrtrace(9, frr_libfrr, schedule_event, m, funcname, schedfrom, fromln,
1007 t_ptr, 0, val, arg, 0);
abf96a87 1008
d62a17ae 1009 assert(m != NULL);
1010
00dffa8c
DL
1011 frr_with_mutex(&m->mtx) {
1012 if (t_ptr && *t_ptr)
d279ef57 1013 /* thread is already scheduled; don't reschedule */
00dffa8c 1014 break;
d62a17ae 1015
60a3efec 1016 thread = thread_get(m, THREAD_EVENT, func, arg, xref);
00dffa8c 1017 frr_with_mutex(&thread->mtx) {
d62a17ae 1018 thread->u.val = val;
c284542b 1019 thread_list_add_tail(&m->event, thread);
d62a17ae 1020 }
d62a17ae 1021
1022 if (t_ptr) {
1023 *t_ptr = thread;
1024 thread->ref = t_ptr;
1025 }
1026
1027 AWAKEN(m);
1028 }
d62a17ae 1029
1030 return thread;
718e3744 1031}
1032
63ccb9cb
QY
1033/* Thread cancellation ------------------------------------------------------ */
1034
8797240e
QY
1035/**
1036 * NOT's out the .events field of pollfd corresponding to the given file
1037 * descriptor. The event to be NOT'd is passed in the 'state' parameter.
1038 *
1039 * This needs to happen for both copies of pollfd's. See 'thread_fetch'
1040 * implementation for details.
1041 *
1042 * @param master
1043 * @param fd
1044 * @param state the event to cancel. One or more (OR'd together) of the
1045 * following:
1046 * - POLLIN
1047 * - POLLOUT
1048 */
d62a17ae 1049static void thread_cancel_rw(struct thread_master *master, int fd, short state)
0a95a0d0 1050{
42d74538
QY
1051 bool found = false;
1052
d62a17ae 1053 /* Cancel POLLHUP too just in case some bozo set it */
1054 state |= POLLHUP;
1055
1056 /* find the index of corresponding pollfd */
1057 nfds_t i;
1058
1059 for (i = 0; i < master->handler.pfdcount; i++)
42d74538
QY
1060 if (master->handler.pfds[i].fd == fd) {
1061 found = true;
d62a17ae 1062 break;
42d74538
QY
1063 }
1064
1065 if (!found) {
1066 zlog_debug(
1067 "[!] Received cancellation request for nonexistent rw job");
1068 zlog_debug("[!] threadmaster: %s | fd: %d",
996c9314 1069 master->name ? master->name : "", fd);
42d74538
QY
1070 return;
1071 }
d62a17ae 1072
1073 /* NOT out event. */
1074 master->handler.pfds[i].events &= ~(state);
1075
1076 /* If all events are canceled, delete / resize the pollfd array. */
1077 if (master->handler.pfds[i].events == 0) {
1078 memmove(master->handler.pfds + i, master->handler.pfds + i + 1,
1079 (master->handler.pfdcount - i - 1)
1080 * sizeof(struct pollfd));
1081 master->handler.pfdcount--;
e985cda0
S
1082 master->handler.pfds[master->handler.pfdcount].fd = 0;
1083 master->handler.pfds[master->handler.pfdcount].events = 0;
d62a17ae 1084 }
1085
1086 /* If we have the same pollfd in the copy, perform the same operations,
1087 * otherwise return. */
1088 if (i >= master->handler.copycount)
1089 return;
1090
1091 master->handler.copy[i].events &= ~(state);
1092
1093 if (master->handler.copy[i].events == 0) {
1094 memmove(master->handler.copy + i, master->handler.copy + i + 1,
1095 (master->handler.copycount - i - 1)
1096 * sizeof(struct pollfd));
1097 master->handler.copycount--;
e985cda0
S
1098 master->handler.copy[master->handler.copycount].fd = 0;
1099 master->handler.copy[master->handler.copycount].events = 0;
d62a17ae 1100 }
0a95a0d0
DS
1101}
1102
1189d95f 1103/**
63ccb9cb 1104 * Process cancellation requests.
1189d95f 1105 *
63ccb9cb
QY
1106 * This may only be run from the pthread which owns the thread_master.
1107 *
1108 * @param master the thread master to process
1109 * @REQUIRE master->mtx
1189d95f 1110 */
d62a17ae 1111static void do_thread_cancel(struct thread_master *master)
718e3744 1112{
c284542b 1113 struct thread_list_head *list = NULL;
d62a17ae 1114 struct thread **thread_array = NULL;
1115 struct thread *thread;
1116
1117 struct cancel_req *cr;
1118 struct listnode *ln;
1119 for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
d279ef57
DS
1120 /*
1121 * If this is an event object cancellation, linear search
1122 * through event list deleting any events which have the
1123 * specified argument. We also need to check every thread
1124 * in the ready queue.
1125 */
d62a17ae 1126 if (cr->eventobj) {
1127 struct thread *t;
c284542b 1128
81fddbe7 1129 frr_each_safe(thread_list, &master->event, t) {
c284542b
DL
1130 if (t->arg != cr->eventobj)
1131 continue;
1132 thread_list_del(&master->event, t);
1133 if (t->ref)
1134 *t->ref = NULL;
1135 thread_add_unuse(master, t);
d62a17ae 1136 }
1137
81fddbe7 1138 frr_each_safe(thread_list, &master->ready, t) {
c284542b
DL
1139 if (t->arg != cr->eventobj)
1140 continue;
1141 thread_list_del(&master->ready, t);
1142 if (t->ref)
1143 *t->ref = NULL;
1144 thread_add_unuse(master, t);
d62a17ae 1145 }
1146 continue;
1147 }
1148
d279ef57
DS
1149 /*
1150 * The pointer varies depending on whether the cancellation
1151 * request was made asynchronously or not. If it was, we
1152 * need to check whether the thread even exists anymore
1153 * before cancelling it.
1154 */
d62a17ae 1155 thread = (cr->thread) ? cr->thread : *cr->threadref;
1156
1157 if (!thread)
1158 continue;
1159
1160 /* Determine the appropriate queue to cancel the thread from */
1161 switch (thread->type) {
1162 case THREAD_READ:
1163 thread_cancel_rw(master, thread->u.fd, POLLIN);
1164 thread_array = master->read;
1165 break;
1166 case THREAD_WRITE:
1167 thread_cancel_rw(master, thread->u.fd, POLLOUT);
1168 thread_array = master->write;
1169 break;
1170 case THREAD_TIMER:
27d29ced 1171 thread_timer_list_del(&master->timer, thread);
d62a17ae 1172 break;
1173 case THREAD_EVENT:
1174 list = &master->event;
1175 break;
1176 case THREAD_READY:
1177 list = &master->ready;
1178 break;
1179 default:
1180 continue;
1181 break;
1182 }
1183
27d29ced 1184 if (list) {
c284542b 1185 thread_list_del(list, thread);
d62a17ae 1186 } else if (thread_array) {
1187 thread_array[thread->u.fd] = NULL;
d62a17ae 1188 }
1189
1190 if (thread->ref)
1191 *thread->ref = NULL;
1192
1193 thread_add_unuse(thread->master, thread);
1194 }
1195
1196 /* Delete and free all cancellation requests */
41b21bfa
MS
1197 if (master->cancel_req)
1198 list_delete_all_node(master->cancel_req);
d62a17ae 1199
1200 /* Wake up any threads which may be blocked in thread_cancel_async() */
1201 master->canceled = true;
1202 pthread_cond_broadcast(&master->cancel_cond);
718e3744 1203}
1204
63ccb9cb
QY
1205/**
1206 * Cancel any events which have the specified argument.
1207 *
1208 * MT-Unsafe
1209 *
1210 * @param m the thread_master to cancel from
1211 * @param arg the argument passed when creating the event
1212 */
d62a17ae 1213void thread_cancel_event(struct thread_master *master, void *arg)
718e3744 1214{
d62a17ae 1215 assert(master->owner == pthread_self());
1216
00dffa8c 1217 frr_with_mutex(&master->mtx) {
d62a17ae 1218 struct cancel_req *cr =
1219 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1220 cr->eventobj = arg;
1221 listnode_add(master->cancel_req, cr);
1222 do_thread_cancel(master);
1223 }
63ccb9cb 1224}
1189d95f 1225
63ccb9cb
QY
1226/**
1227 * Cancel a specific task.
1228 *
1229 * MT-Unsafe
1230 *
1231 * @param thread task to cancel
1232 */
b3d6bc6e 1233void thread_cancel(struct thread **thread)
63ccb9cb 1234{
b3d6bc6e
MS
1235 struct thread_master *master;
1236
1237 if (thread == NULL || *thread == NULL)
1238 return;
1239
1240 master = (*thread)->master;
d62a17ae 1241
b4d6e855
QY
1242 frrtrace(9, frr_libfrr, thread_cancel, master, (*thread)->funcname,
1243 (*thread)->schedfrom, (*thread)->schedfrom_line, NULL, (*thread)->u.fd,
1244 (*thread)->u.val, (*thread)->arg, (*thread)->u.sands.tv_sec);
abf96a87 1245
6ed04aa2
DS
1246 assert(master->owner == pthread_self());
1247
00dffa8c 1248 frr_with_mutex(&master->mtx) {
d62a17ae 1249 struct cancel_req *cr =
1250 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
b3d6bc6e 1251 cr->thread = *thread;
6ed04aa2
DS
1252 listnode_add(master->cancel_req, cr);
1253 do_thread_cancel(master);
d62a17ae 1254 }
b3d6bc6e
MS
1255
1256 *thread = NULL;
63ccb9cb 1257}
1189d95f 1258
63ccb9cb
QY
1259/**
1260 * Asynchronous cancellation.
1261 *
8797240e
QY
1262 * Called with either a struct thread ** or void * to an event argument,
1263 * this function posts the correct cancellation request and blocks until it is
1264 * serviced.
63ccb9cb
QY
1265 *
1266 * If the thread is currently running, execution blocks until it completes.
1267 *
8797240e
QY
1268 * The last two parameters are mutually exclusive, i.e. if you pass one the
1269 * other must be NULL.
1270 *
1271 * When the cancellation procedure executes on the target thread_master, the
1272 * thread * provided is checked for nullity. If it is null, the thread is
1273 * assumed to no longer exist and the cancellation request is a no-op. Thus
1274 * users of this API must pass a back-reference when scheduling the original
1275 * task.
1276 *
63ccb9cb
QY
1277 * MT-Safe
1278 *
8797240e
QY
1279 * @param master the thread master with the relevant event / task
1280 * @param thread pointer to thread to cancel
1281 * @param eventobj the event
63ccb9cb 1282 */
d62a17ae 1283void thread_cancel_async(struct thread_master *master, struct thread **thread,
1284 void *eventobj)
63ccb9cb 1285{
d62a17ae 1286 assert(!(thread && eventobj) && (thread || eventobj));
abf96a87
QY
1287
1288 if (thread && *thread)
c7bb4f00
QY
1289 frrtrace(9, frr_libfrr, thread_cancel_async, master,
1290 (*thread)->funcname, (*thread)->schedfrom,
1291 (*thread)->schedfrom_line, NULL, (*thread)->u.fd,
1292 (*thread)->u.val, (*thread)->arg,
1293 (*thread)->u.sands.tv_sec);
abf96a87 1294 else
c7bb4f00
QY
1295 frrtrace(9, frr_libfrr, thread_cancel_async, master, NULL, NULL,
1296 0, NULL, 0, 0, eventobj, 0);
abf96a87 1297
d62a17ae 1298 assert(master->owner != pthread_self());
1299
00dffa8c 1300 frr_with_mutex(&master->mtx) {
d62a17ae 1301 master->canceled = false;
1302
1303 if (thread) {
1304 struct cancel_req *cr =
1305 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1306 cr->threadref = thread;
1307 listnode_add(master->cancel_req, cr);
1308 } else if (eventobj) {
1309 struct cancel_req *cr =
1310 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1311 cr->eventobj = eventobj;
1312 listnode_add(master->cancel_req, cr);
1313 }
1314 AWAKEN(master);
1315
1316 while (!master->canceled)
1317 pthread_cond_wait(&master->cancel_cond, &master->mtx);
1318 }
50478845
MS
1319
1320 if (thread)
1321 *thread = NULL;
718e3744 1322}
63ccb9cb 1323/* ------------------------------------------------------------------------- */
718e3744 1324
27d29ced 1325static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers,
d62a17ae 1326 struct timeval *timer_val)
718e3744 1327{
27d29ced
DL
1328 if (!thread_timer_list_count(timers))
1329 return NULL;
1330
1331 struct thread *next_timer = thread_timer_list_first(timers);
1332 monotime_until(&next_timer->u.sands, timer_val);
1333 return timer_val;
718e3744 1334}
718e3744 1335
d62a17ae 1336static struct thread *thread_run(struct thread_master *m, struct thread *thread,
1337 struct thread *fetch)
718e3744 1338{
d62a17ae 1339 *fetch = *thread;
1340 thread_add_unuse(m, thread);
1341 return fetch;
718e3744 1342}
1343
d62a17ae 1344static int thread_process_io_helper(struct thread_master *m,
45f3d590
DS
1345 struct thread *thread, short state,
1346 short actual_state, int pos)
5d4ccd4e 1347{
d62a17ae 1348 struct thread **thread_array;
1349
45f3d590
DS
1350 /*
1351 * poll() clears the .events field, but the pollfd array we
1352 * pass to poll() is a copy of the one used to schedule threads.
1353 * We need to synchronize state between the two here by applying
1354 * the same changes poll() made on the copy of the "real" pollfd
1355 * array.
1356 *
1357 * This cleans up a possible infinite loop where we refuse
1358 * to respond to a poll event but poll is insistent that
1359 * we should.
1360 */
1361 m->handler.pfds[pos].events &= ~(state);
1362
1363 if (!thread) {
1364 if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
1365 flog_err(EC_LIB_NO_THREAD,
1366 "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n",
1367 m->handler.pfds[pos].fd, actual_state);
d62a17ae 1368 return 0;
45f3d590 1369 }
d62a17ae 1370
1371 if (thread->type == THREAD_READ)
1372 thread_array = m->read;
1373 else
1374 thread_array = m->write;
1375
1376 thread_array[thread->u.fd] = NULL;
c284542b 1377 thread_list_add_tail(&m->ready, thread);
d62a17ae 1378 thread->type = THREAD_READY;
45f3d590 1379
d62a17ae 1380 return 1;
5d4ccd4e
DS
1381}
1382
8797240e
QY
1383/**
1384 * Process I/O events.
1385 *
1386 * Walks through file descriptor array looking for those pollfds whose .revents
1387 * field has something interesting. Deletes any invalid file descriptors.
1388 *
1389 * @param m the thread master
1390 * @param num the number of active file descriptors (return value of poll())
1391 */
d62a17ae 1392static void thread_process_io(struct thread_master *m, unsigned int num)
0a95a0d0 1393{
d62a17ae 1394 unsigned int ready = 0;
1395 struct pollfd *pfds = m->handler.copy;
1396
1397 for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) {
1398 /* no event for current fd? immediately continue */
1399 if (pfds[i].revents == 0)
1400 continue;
1401
1402 ready++;
1403
d279ef57
DS
1404 /*
1405 * Unless someone has called thread_cancel from another
1406 * pthread, the only thing that could have changed in
1407 * m->handler.pfds while we were asleep is the .events
1408 * field in a given pollfd. Barring thread_cancel() that
1409 * value should be a superset of the values we have in our
1410 * copy, so there's no need to update it. Similarily,
1411 * barring deletion, the fd should still be a valid index
1412 * into the master's pfds.
d142453d
DS
1413 *
1414 * We are including POLLERR here to do a READ event
1415 * this is because the read should fail and the
1416 * read function should handle it appropriately
d279ef57 1417 */
d142453d 1418 if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
d62a17ae 1419 thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
45f3d590
DS
1420 pfds[i].revents, i);
1421 }
d62a17ae 1422 if (pfds[i].revents & POLLOUT)
1423 thread_process_io_helper(m, m->write[pfds[i].fd],
45f3d590 1424 POLLOUT, pfds[i].revents, i);
d62a17ae 1425
1426 /* if one of our file descriptors is garbage, remove the same
1427 * from
1428 * both pfds + update sizes and index */
1429 if (pfds[i].revents & POLLNVAL) {
1430 memmove(m->handler.pfds + i, m->handler.pfds + i + 1,
1431 (m->handler.pfdcount - i - 1)
1432 * sizeof(struct pollfd));
1433 m->handler.pfdcount--;
e985cda0
S
1434 m->handler.pfds[m->handler.pfdcount].fd = 0;
1435 m->handler.pfds[m->handler.pfdcount].events = 0;
d62a17ae 1436
1437 memmove(pfds + i, pfds + i + 1,
1438 (m->handler.copycount - i - 1)
1439 * sizeof(struct pollfd));
1440 m->handler.copycount--;
e985cda0
S
1441 m->handler.copy[m->handler.copycount].fd = 0;
1442 m->handler.copy[m->handler.copycount].events = 0;
d62a17ae 1443
1444 i--;
1445 }
1446 }
718e3744 1447}
1448
8b70d0b0 1449/* Add all timers that have popped to the ready list. */
27d29ced 1450static unsigned int thread_process_timers(struct thread_timer_list_head *timers,
d62a17ae 1451 struct timeval *timenow)
a48b4e6d 1452{
d62a17ae 1453 struct thread *thread;
1454 unsigned int ready = 0;
1455
27d29ced 1456 while ((thread = thread_timer_list_first(timers))) {
d62a17ae 1457 if (timercmp(timenow, &thread->u.sands, <))
1458 return ready;
27d29ced 1459 thread_timer_list_pop(timers);
d62a17ae 1460 thread->type = THREAD_READY;
c284542b 1461 thread_list_add_tail(&thread->master->ready, thread);
d62a17ae 1462 ready++;
1463 }
1464 return ready;
a48b4e6d 1465}
1466
2613abe6 1467/* process a list en masse, e.g. for event thread lists */
c284542b 1468static unsigned int thread_process(struct thread_list_head *list)
2613abe6 1469{
d62a17ae 1470 struct thread *thread;
d62a17ae 1471 unsigned int ready = 0;
1472
c284542b 1473 while ((thread = thread_list_pop(list))) {
d62a17ae 1474 thread->type = THREAD_READY;
c284542b 1475 thread_list_add_tail(&thread->master->ready, thread);
d62a17ae 1476 ready++;
1477 }
1478 return ready;
2613abe6
PJ
1479}
1480
1481
718e3744 1482/* Fetch next ready thread. */
d62a17ae 1483struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
718e3744 1484{
d62a17ae 1485 struct thread *thread = NULL;
1486 struct timeval now;
1487 struct timeval zerotime = {0, 0};
1488 struct timeval tv;
1489 struct timeval *tw = NULL;
d81ca9a3 1490 bool eintr_p = false;
d62a17ae 1491 int num = 0;
1492
1493 do {
1494 /* Handle signals if any */
1495 if (m->handle_signals)
1496 quagga_sigevent_process();
1497
1498 pthread_mutex_lock(&m->mtx);
1499
1500 /* Process any pending cancellation requests */
1501 do_thread_cancel(m);
1502
e3c9529e
QY
1503 /*
1504 * Attempt to flush ready queue before going into poll().
1505 * This is performance-critical. Think twice before modifying.
1506 */
c284542b 1507 if ((thread = thread_list_pop(&m->ready))) {
e3c9529e
QY
1508 fetch = thread_run(m, thread, fetch);
1509 if (fetch->ref)
1510 *fetch->ref = NULL;
1511 pthread_mutex_unlock(&m->mtx);
1512 break;
1513 }
1514
1515 /* otherwise, tick through scheduling sequence */
1516
bca37d17
QY
1517 /*
1518 * Post events to ready queue. This must come before the
1519 * following block since events should occur immediately
1520 */
d62a17ae 1521 thread_process(&m->event);
1522
bca37d17
QY
1523 /*
1524 * If there are no tasks on the ready queue, we will poll()
1525 * until a timer expires or we receive I/O, whichever comes
1526 * first. The strategy for doing this is:
d62a17ae 1527 *
1528 * - If there are events pending, set the poll() timeout to zero
1529 * - If there are no events pending, but there are timers
d279ef57
DS
1530 * pending, set the timeout to the smallest remaining time on
1531 * any timer.
d62a17ae 1532 * - If there are neither timers nor events pending, but there
d279ef57 1533 * are file descriptors pending, block indefinitely in poll()
d62a17ae 1534 * - If nothing is pending, it's time for the application to die
1535 *
1536 * In every case except the last, we need to hit poll() at least
bca37d17
QY
1537 * once per loop to avoid starvation by events
1538 */
c284542b 1539 if (!thread_list_count(&m->ready))
27d29ced 1540 tw = thread_timer_wait(&m->timer, &tv);
d62a17ae 1541
c284542b
DL
1542 if (thread_list_count(&m->ready) ||
1543 (tw && !timercmp(tw, &zerotime, >)))
d62a17ae 1544 tw = &zerotime;
1545
1546 if (!tw && m->handler.pfdcount == 0) { /* die */
1547 pthread_mutex_unlock(&m->mtx);
1548 fetch = NULL;
1549 break;
1550 }
1551
bca37d17
QY
1552 /*
1553 * Copy pollfd array + # active pollfds in it. Not necessary to
1554 * copy the array size as this is fixed.
1555 */
d62a17ae 1556 m->handler.copycount = m->handler.pfdcount;
1557 memcpy(m->handler.copy, m->handler.pfds,
1558 m->handler.copycount * sizeof(struct pollfd));
1559
e3c9529e
QY
1560 pthread_mutex_unlock(&m->mtx);
1561 {
d81ca9a3
MS
1562 eintr_p = false;
1563 num = fd_poll(m, tw, &eintr_p);
e3c9529e
QY
1564 }
1565 pthread_mutex_lock(&m->mtx);
d764d2cc 1566
e3c9529e
QY
1567 /* Handle any errors received in poll() */
1568 if (num < 0) {
d81ca9a3 1569 if (eintr_p) {
d62a17ae 1570 pthread_mutex_unlock(&m->mtx);
e3c9529e
QY
1571 /* loop around to signal handler */
1572 continue;
d62a17ae 1573 }
1574
e3c9529e 1575 /* else die */
450971aa 1576 flog_err(EC_LIB_SYSTEM_CALL, "poll() error: %s",
9ef9495e 1577 safe_strerror(errno));
e3c9529e
QY
1578 pthread_mutex_unlock(&m->mtx);
1579 fetch = NULL;
1580 break;
bca37d17 1581 }
d62a17ae 1582
1583 /* Post timers to ready queue. */
1584 monotime(&now);
27d29ced 1585 thread_process_timers(&m->timer, &now);
d62a17ae 1586
1587 /* Post I/O to ready queue. */
1588 if (num > 0)
1589 thread_process_io(m, num);
1590
d62a17ae 1591 pthread_mutex_unlock(&m->mtx);
1592
1593 } while (!thread && m->spin);
1594
1595 return fetch;
718e3744 1596}
1597
d62a17ae 1598static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
62f44022 1599{
d62a17ae 1600 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
1601 + (a.tv_usec - b.tv_usec));
62f44022
QY
1602}
1603
d62a17ae 1604unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
1605 unsigned long *cputime)
718e3744 1606{
d62a17ae 1607 /* This is 'user + sys' time. */
1608 *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
1609 + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
1610 return timeval_elapsed(now->real, start->real);
8b70d0b0 1611}
1612
50596be0
DS
1613/* We should aim to yield after yield milliseconds, which defaults
1614 to THREAD_YIELD_TIME_SLOT .
8b70d0b0 1615 Note: we are using real (wall clock) time for this calculation.
1616 It could be argued that CPU time may make more sense in certain
1617 contexts. The things to consider are whether the thread may have
1618 blocked (in which case wall time increases, but CPU time does not),
1619 or whether the system is heavily loaded with other processes competing
d62a17ae 1620 for CPU time. On balance, wall clock time seems to make sense.
8b70d0b0 1621 Plus it has the added benefit that gettimeofday should be faster
1622 than calling getrusage. */
d62a17ae 1623int thread_should_yield(struct thread *thread)
718e3744 1624{
d62a17ae 1625 int result;
00dffa8c 1626 frr_with_mutex(&thread->mtx) {
d62a17ae 1627 result = monotime_since(&thread->real, NULL)
1628 > (int64_t)thread->yield;
1629 }
d62a17ae 1630 return result;
50596be0
DS
1631}
1632
d62a17ae 1633void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
50596be0 1634{
00dffa8c 1635 frr_with_mutex(&thread->mtx) {
d62a17ae 1636 thread->yield = yield_time;
1637 }
718e3744 1638}
1639
d62a17ae 1640void thread_getrusage(RUSAGE_T *r)
db9c0df9 1641{
231db9a6
DS
1642#if defined RUSAGE_THREAD
1643#define FRR_RUSAGE RUSAGE_THREAD
1644#else
1645#define FRR_RUSAGE RUSAGE_SELF
1646#endif
d62a17ae 1647 monotime(&r->real);
f75e802d 1648#ifndef EXCLUDE_CPU_TIME
231db9a6 1649 getrusage(FRR_RUSAGE, &(r->cpu));
f75e802d 1650#endif
db9c0df9
PJ
1651}
1652
fbcac826
QY
1653/*
1654 * Call a thread.
1655 *
1656 * This function will atomically update the thread's usage history. At present
1657 * this is the only spot where usage history is written. Nevertheless the code
1658 * has been written such that the introduction of writers in the future should
1659 * not need to update it provided the writers atomically perform only the
1660 * operations done here, i.e. updating the total and maximum times. In
1661 * particular, the maximum real and cpu times must be monotonically increasing
1662 * or this code is not correct.
1663 */
d62a17ae 1664void thread_call(struct thread *thread)
718e3744 1665{
f75e802d 1666#ifndef EXCLUDE_CPU_TIME
fbcac826
QY
1667 _Atomic unsigned long realtime, cputime;
1668 unsigned long exp;
1669 unsigned long helper;
f75e802d 1670#endif
d62a17ae 1671 RUSAGE_T before, after;
cc8b13a0 1672
d62a17ae 1673 GETRUSAGE(&before);
1674 thread->real = before.real;
718e3744 1675
c7bb4f00
QY
1676 frrtrace(9, frr_libfrr, thread_call, thread->master, thread->funcname,
1677 thread->schedfrom, thread->schedfrom_line, NULL, thread->u.fd,
1678 thread->u.val, thread->arg, thread->u.sands.tv_sec);
abf96a87 1679
d62a17ae 1680 pthread_setspecific(thread_current, thread);
1681 (*thread->func)(thread);
1682 pthread_setspecific(thread_current, NULL);
718e3744 1683
d62a17ae 1684 GETRUSAGE(&after);
718e3744 1685
f75e802d 1686#ifndef EXCLUDE_CPU_TIME
fbcac826
QY
1687 realtime = thread_consumed_time(&after, &before, &helper);
1688 cputime = helper;
1689
1690 /* update realtime */
1691 atomic_fetch_add_explicit(&thread->hist->real.total, realtime,
1692 memory_order_seq_cst);
1693 exp = atomic_load_explicit(&thread->hist->real.max,
1694 memory_order_seq_cst);
1695 while (exp < realtime
1696 && !atomic_compare_exchange_weak_explicit(
1697 &thread->hist->real.max, &exp, realtime,
1698 memory_order_seq_cst, memory_order_seq_cst))
1699 ;
1700
1701 /* update cputime */
1702 atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime,
1703 memory_order_seq_cst);
1704 exp = atomic_load_explicit(&thread->hist->cpu.max,
1705 memory_order_seq_cst);
1706 while (exp < cputime
1707 && !atomic_compare_exchange_weak_explicit(
1708 &thread->hist->cpu.max, &exp, cputime,
1709 memory_order_seq_cst, memory_order_seq_cst))
1710 ;
1711
1712 atomic_fetch_add_explicit(&thread->hist->total_calls, 1,
1713 memory_order_seq_cst);
1714 atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type,
1715 memory_order_seq_cst);
718e3744 1716
924b9229 1717#ifdef CONSUMED_TIME_CHECK
d62a17ae 1718 if (realtime > CONSUMED_TIME_CHECK) {
1719 /*
1720 * We have a CPU Hog on our hands.
1721 * Whinge about it now, so we're aware this is yet another task
1722 * to fix.
1723 */
9ef9495e 1724 flog_warn(
450971aa 1725 EC_LIB_SLOW_THREAD,
d62a17ae 1726 "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
60a3efec 1727 thread->xref->funcname, (unsigned long)thread->func,
d62a17ae 1728 realtime / 1000, cputime / 1000);
1729 }
924b9229 1730#endif /* CONSUMED_TIME_CHECK */
f75e802d 1731#endif /* Exclude CPU Time */
718e3744 1732}
1733
1734/* Execute thread */
60a3efec
DL
1735void _thread_execute(const struct xref_threadsched *xref,
1736 struct thread_master *m, int (*func)(struct thread *),
1737 void *arg, int val)
718e3744 1738{
c4345fbf 1739 struct thread *thread;
718e3744 1740
c4345fbf 1741 /* Get or allocate new thread to execute. */
00dffa8c 1742 frr_with_mutex(&m->mtx) {
60a3efec 1743 thread = thread_get(m, THREAD_EVENT, func, arg, xref);
9c7753e4 1744
c4345fbf 1745 /* Set its event value. */
00dffa8c 1746 frr_with_mutex(&thread->mtx) {
c4345fbf
RZ
1747 thread->add_type = THREAD_EXECUTE;
1748 thread->u.val = val;
1749 thread->ref = &thread;
1750 }
c4345fbf 1751 }
f7c62e11 1752
c4345fbf
RZ
1753 /* Execute thread doing all accounting. */
1754 thread_call(thread);
9c7753e4 1755
c4345fbf
RZ
1756 /* Give back or free thread. */
1757 thread_add_unuse(m, thread);
718e3744 1758}
1543c387
MS
1759
1760/* Debug signal mask - if 'sigs' is NULL, use current effective mask. */
1761void debug_signals(const sigset_t *sigs)
1762{
1763 int i, found;
1764 sigset_t tmpsigs;
1765 char buf[300];
1766
1767 /*
1768 * We're only looking at the non-realtime signals here, so we need
1769 * some limit value. Platform differences mean at some point we just
1770 * need to pick a reasonable value.
1771 */
1772#if defined SIGRTMIN
1773# define LAST_SIGNAL SIGRTMIN
1774#else
1775# define LAST_SIGNAL 32
1776#endif
1777
1778
1779 if (sigs == NULL) {
1780 sigemptyset(&tmpsigs);
1781 pthread_sigmask(SIG_BLOCK, NULL, &tmpsigs);
1782 sigs = &tmpsigs;
1783 }
1784
1785 found = 0;
1786 buf[0] = '\0';
1787
1788 for (i = 0; i < LAST_SIGNAL; i++) {
1789 char tmp[20];
1790
1791 if (sigismember(sigs, i) > 0) {
1792 if (found > 0)
1793 strlcat(buf, ",", sizeof(buf));
1794 snprintf(tmp, sizeof(tmp), "%d", i);
1795 strlcat(buf, tmp, sizeof(buf));
1796 found++;
1797 }
1798 }
1799
1800 if (found == 0)
1801 snprintf(buf, sizeof(buf), "<none>");
1802
1803 zlog_debug("%s: %s", __func__, buf);
1804}