]> git.proxmox.com Git - mirror_frr.git/blame - lib/thread.c
Merge branch 'quagga' into google-bgp-multipath
[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 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22/* #define DEBUG */
23
24#include <zebra.h>
25
26#include "thread.h"
27#include "memory.h"
28#include "log.h"
e04ab74d 29#include "hash.h"
30#include "command.h"
05c447dd 31#include "sigevent.h"
e04ab74d 32\f
db9c0df9 33/* Recent absolute time of day */
8b70d0b0 34struct timeval recent_time;
db9c0df9
PJ
35static struct timeval last_recent_time;
36/* Relative time, since startup */
37static struct timeval relative_time;
38static struct timeval relative_time_base;
39/* init flag */
40static unsigned short timers_inited;
41\f
e04ab74d 42static struct hash *cpu_record = NULL;
718e3744 43\f
44/* Struct timeval's tv_usec one second value. */
45#define TIMER_SECOND_MICRO 1000000L
46
8b70d0b0 47/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
48 And change negative values to 0. */
a48b4e6d 49static struct timeval
718e3744 50timeval_adjust (struct timeval a)
51{
52 while (a.tv_usec >= TIMER_SECOND_MICRO)
53 {
54 a.tv_usec -= TIMER_SECOND_MICRO;
55 a.tv_sec++;
56 }
57
58 while (a.tv_usec < 0)
59 {
60 a.tv_usec += TIMER_SECOND_MICRO;
61 a.tv_sec--;
62 }
63
64 if (a.tv_sec < 0)
8b70d0b0 65 /* Change negative timeouts to 0. */
66 a.tv_sec = a.tv_usec = 0;
718e3744 67
68 return a;
69}
70
71static struct timeval
72timeval_subtract (struct timeval a, struct timeval b)
73{
74 struct timeval ret;
75
76 ret.tv_usec = a.tv_usec - b.tv_usec;
77 ret.tv_sec = a.tv_sec - b.tv_sec;
78
79 return timeval_adjust (ret);
80}
81
8b70d0b0 82static long
718e3744 83timeval_cmp (struct timeval a, struct timeval b)
84{
85 return (a.tv_sec == b.tv_sec
86 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
87}
88
89static unsigned long
90timeval_elapsed (struct timeval a, struct timeval b)
91{
92 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
93 + (a.tv_usec - b.tv_usec));
94}
95\f
db9c0df9
PJ
96#ifndef HAVE_CLOCK_MONOTONIC
97static void
98quagga_gettimeofday_relative_adjust (void)
99{
100 struct timeval diff;
101 if (timeval_cmp (recent_time, last_recent_time) < 0)
102 {
103 relative_time.tv_sec++;
104 relative_time.tv_usec = 0;
105 }
106 else
107 {
108 diff = timeval_subtract (recent_time, last_recent_time);
109 relative_time.tv_sec += diff.tv_sec;
110 relative_time.tv_usec += diff.tv_usec;
111 relative_time = timeval_adjust (relative_time);
112 }
113 last_recent_time = recent_time;
114}
115#endif /* !HAVE_CLOCK_MONOTONIC */
116
117/* gettimeofday wrapper, to keep recent_time updated */
118static int
119quagga_gettimeofday (struct timeval *tv)
120{
121 int ret;
122
123 assert (tv);
124
125 if (!(ret = gettimeofday (&recent_time, NULL)))
126 {
127 /* init... */
128 if (!timers_inited)
129 {
130 relative_time_base = last_recent_time = recent_time;
131 timers_inited = 1;
132 }
133 /* avoid copy if user passed recent_time pointer.. */
134 if (tv != &recent_time)
135 *tv = recent_time;
136 return 0;
137 }
138 return ret;
139}
140
141static int
142quagga_get_relative (struct timeval *tv)
143{
144 int ret;
145
146#ifdef HAVE_CLOCK_MONOTONIC
147 {
148 struct timespec tp;
149 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
150 {
151 relative_time.tv_sec = tp.tv_sec;
152 relative_time.tv_usec = tp.tv_nsec / 1000;
153 }
154 }
155#else /* !HAVE_CLOCK_MONOTONIC */
156 if (!(ret = quagga_gettimeofday (&recent_time)))
157 quagga_gettimeofday_relative_adjust();
158#endif /* HAVE_CLOCK_MONOTONIC */
159
160 if (tv)
161 *tv = relative_time;
162
163 return ret;
164}
165
166/* Get absolute time stamp, but in terms of the internal timer
167 * Could be wrong, but at least won't go back.
168 */
169static void
170quagga_real_stabilised (struct timeval *tv)
171{
172 *tv = relative_time_base;
173 tv->tv_sec += relative_time.tv_sec;
174 tv->tv_usec += relative_time.tv_usec;
175 *tv = timeval_adjust (*tv);
176}
177
178/* Exported Quagga timestamp function.
179 * Modelled on POSIX clock_gettime.
180 */
181int
182quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
183{
184 switch (clkid)
185 {
186 case QUAGGA_CLK_REALTIME:
187 return quagga_gettimeofday (tv);
188 case QUAGGA_CLK_MONOTONIC:
189 return quagga_get_relative (tv);
190 case QUAGGA_CLK_REALTIME_STABILISED:
191 quagga_real_stabilised (tv);
192 return 0;
193 default:
194 errno = EINVAL;
195 return -1;
196 }
197}
198
199/* time_t value in terms of stabilised absolute time.
200 * replacement for POSIX time()
201 */
202time_t
203quagga_time (time_t *t)
204{
205 struct timeval tv;
206 quagga_real_stabilised (&tv);
207 if (t)
208 *t = tv.tv_sec;
209 return tv.tv_sec;
210}
211
212/* Public export of recent_relative_time by value */
213struct timeval
214recent_relative_time (void)
215{
216 return relative_time;
217}
218\f
a48b4e6d 219static unsigned int
e04ab74d 220cpu_record_hash_key (struct cpu_thread_history *a)
221{
8cc4198f 222 return (uintptr_t) a->func;
e04ab74d 223}
224
225static int
ffe11cfb
SH
226cpu_record_hash_cmp (const struct cpu_thread_history *a,
227 const struct cpu_thread_history *b)
e04ab74d 228{
229 return a->func == b->func;
230}
231
8cc4198f 232static void *
e04ab74d 233cpu_record_hash_alloc (struct cpu_thread_history *a)
234{
235 struct cpu_thread_history *new;
039b9577 236 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
e04ab74d 237 new->func = a->func;
9d11a19e 238 new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);
e04ab74d 239 return new;
240}
241
228da428
CC
242static void
243cpu_record_hash_free (void *a)
244{
245 struct cpu_thread_history *hist = a;
246
247 XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname);
248 XFREE (MTYPE_THREAD_STATS, hist);
249}
250
f63f06da 251static void
e04ab74d 252vty_out_cpu_thread_history(struct vty* vty,
253 struct cpu_thread_history *a)
254{
8b70d0b0 255#ifdef HAVE_RUSAGE
256 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
257 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
258 a->cpu.total/a->total_calls, a->cpu.max,
259 a->real.total/a->total_calls, a->real.max);
260#else
261 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
262 a->real.total/1000, a->real.total%1000, a->total_calls,
263 a->real.total/a->total_calls, a->real.max);
264#endif
265 vty_out(vty, " %c%c%c%c%c%c %s%s",
e04ab74d 266 a->types & (1 << THREAD_READ) ? 'R':' ',
267 a->types & (1 << THREAD_WRITE) ? 'W':' ',
268 a->types & (1 << THREAD_TIMER) ? 'T':' ',
269 a->types & (1 << THREAD_EVENT) ? 'E':' ',
270 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
a48b4e6d 271 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
e04ab74d 272 a->funcname, VTY_NEWLINE);
273}
274
275static void
276cpu_record_hash_print(struct hash_backet *bucket,
277 void *args[])
278{
279 struct cpu_thread_history *totals = args[0];
280 struct vty *vty = args[1];
41b2373c 281 thread_type *filter = args[2];
e04ab74d 282 struct cpu_thread_history *a = bucket->data;
a48b4e6d 283
e04ab74d 284 a = bucket->data;
285 if ( !(a->types & *filter) )
286 return;
287 vty_out_cpu_thread_history(vty,a);
e04ab74d 288 totals->total_calls += a->total_calls;
8b70d0b0 289 totals->real.total += a->real.total;
290 if (totals->real.max < a->real.max)
291 totals->real.max = a->real.max;
292#ifdef HAVE_RUSAGE
293 totals->cpu.total += a->cpu.total;
294 if (totals->cpu.max < a->cpu.max)
295 totals->cpu.max = a->cpu.max;
296#endif
e04ab74d 297}
298
299static void
41b2373c 300cpu_record_print(struct vty *vty, thread_type filter)
e04ab74d 301{
302 struct cpu_thread_history tmp;
303 void *args[3] = {&tmp, vty, &filter};
304
305 memset(&tmp, 0, sizeof tmp);
8526100e 306 tmp.funcname = (char *)"TOTAL";
e04ab74d 307 tmp.types = filter;
308
8b70d0b0 309#ifdef HAVE_RUSAGE
310 vty_out(vty, "%21s %18s %18s%s",
311 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
312#endif
313 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
314#ifdef HAVE_RUSAGE
315 vty_out(vty, " Avg uSec Max uSecs");
316#endif
317 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
e04ab74d 318 hash_iterate(cpu_record,
319 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
320 args);
321
322 if (tmp.total_calls > 0)
323 vty_out_cpu_thread_history(vty, &tmp);
324}
325
326DEFUN(show_thread_cpu,
327 show_thread_cpu_cmd,
328 "show thread cpu [FILTER]",
329 SHOW_STR
330 "Thread information\n"
331 "Thread CPU usage\n"
a48b4e6d 332 "Display filter (rwtexb)\n")
e04ab74d 333{
334 int i = 0;
41b2373c 335 thread_type filter = (thread_type) -1U;
e04ab74d 336
337 if (argc > 0)
338 {
339 filter = 0;
340 while (argv[0][i] != '\0')
341 {
342 switch ( argv[0][i] )
343 {
344 case 'r':
345 case 'R':
346 filter |= (1 << THREAD_READ);
347 break;
348 case 'w':
349 case 'W':
350 filter |= (1 << THREAD_WRITE);
351 break;
352 case 't':
353 case 'T':
354 filter |= (1 << THREAD_TIMER);
355 break;
356 case 'e':
357 case 'E':
358 filter |= (1 << THREAD_EVENT);
359 break;
360 case 'x':
361 case 'X':
362 filter |= (1 << THREAD_EXECUTE);
363 break;
a48b4e6d 364 case 'b':
365 case 'B':
366 filter |= (1 << THREAD_BACKGROUND);
367 break;
e04ab74d 368 default:
369 break;
370 }
371 ++i;
372 }
373 if (filter == 0)
374 {
a48b4e6d 375 vty_out(vty, "Invalid filter \"%s\" specified,"
376 " must contain at least one of 'RWTEXB'%s",
e04ab74d 377 argv[0], VTY_NEWLINE);
378 return CMD_WARNING;
379 }
380 }
381
382 cpu_record_print(vty, filter);
383 return CMD_SUCCESS;
384}
e276eb82
PJ
385
386static void
387cpu_record_hash_clear (struct hash_backet *bucket,
388 void *args)
389{
390 thread_type *filter = args;
391 struct cpu_thread_history *a = bucket->data;
392
393 a = bucket->data;
394 if ( !(a->types & *filter) )
395 return;
396
397 hash_release (cpu_record, bucket->data);
398}
399
400static void
401cpu_record_clear (thread_type filter)
402{
403 thread_type *tmp = &filter;
404 hash_iterate (cpu_record,
405 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
406 tmp);
407}
408
409DEFUN(clear_thread_cpu,
410 clear_thread_cpu_cmd,
411 "clear thread cpu [FILTER]",
412 "Clear stored data\n"
413 "Thread information\n"
414 "Thread CPU usage\n"
415 "Display filter (rwtexb)\n")
416{
417 int i = 0;
418 thread_type filter = (thread_type) -1U;
419
420 if (argc > 0)
421 {
422 filter = 0;
423 while (argv[0][i] != '\0')
424 {
425 switch ( argv[0][i] )
426 {
427 case 'r':
428 case 'R':
429 filter |= (1 << THREAD_READ);
430 break;
431 case 'w':
432 case 'W':
433 filter |= (1 << THREAD_WRITE);
434 break;
435 case 't':
436 case 'T':
437 filter |= (1 << THREAD_TIMER);
438 break;
439 case 'e':
440 case 'E':
441 filter |= (1 << THREAD_EVENT);
442 break;
443 case 'x':
444 case 'X':
445 filter |= (1 << THREAD_EXECUTE);
446 break;
447 case 'b':
448 case 'B':
449 filter |= (1 << THREAD_BACKGROUND);
450 break;
451 default:
452 break;
453 }
454 ++i;
455 }
456 if (filter == 0)
457 {
458 vty_out(vty, "Invalid filter \"%s\" specified,"
459 " must contain at least one of 'RWTEXB'%s",
460 argv[0], VTY_NEWLINE);
461 return CMD_WARNING;
462 }
463 }
464
465 cpu_record_clear (filter);
466 return CMD_SUCCESS;
467}
e04ab74d 468\f
718e3744 469/* List allocation and head/tail print out. */
470static void
471thread_list_debug (struct thread_list *list)
472{
473 printf ("count [%d] head [%p] tail [%p]\n",
474 list->count, list->head, list->tail);
475}
476
477/* Debug print for thread_master. */
8cc4198f 478static void __attribute__ ((unused))
718e3744 479thread_master_debug (struct thread_master *m)
480{
481 printf ("-----------\n");
482 printf ("readlist : ");
483 thread_list_debug (&m->read);
484 printf ("writelist : ");
485 thread_list_debug (&m->write);
486 printf ("timerlist : ");
487 thread_list_debug (&m->timer);
488 printf ("eventlist : ");
489 thread_list_debug (&m->event);
490 printf ("unuselist : ");
491 thread_list_debug (&m->unuse);
a48b4e6d 492 printf ("bgndlist : ");
493 thread_list_debug (&m->background);
718e3744 494 printf ("total alloc: [%ld]\n", m->alloc);
495 printf ("-----------\n");
496}
497\f
498/* Allocate new thread master. */
499struct thread_master *
500thread_master_create ()
501{
e04ab74d 502 if (cpu_record == NULL)
8cc4198f 503 cpu_record
504 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
ffe11cfb 505 (int (*) (const void *, const void *))cpu_record_hash_cmp);
a48b4e6d 506
718e3744 507 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
508 sizeof (struct thread_master));
509}
510
511/* Add a new thread to the list. */
512static void
513thread_list_add (struct thread_list *list, struct thread *thread)
514{
515 thread->next = NULL;
516 thread->prev = list->tail;
517 if (list->tail)
518 list->tail->next = thread;
519 else
520 list->head = thread;
521 list->tail = thread;
522 list->count++;
523}
524
525/* Add a new thread just before the point. */
526static void
527thread_list_add_before (struct thread_list *list,
528 struct thread *point,
529 struct thread *thread)
530{
531 thread->next = point;
532 thread->prev = point->prev;
533 if (point->prev)
534 point->prev->next = thread;
535 else
536 list->head = thread;
537 point->prev = thread;
538 list->count++;
539}
540
541/* Delete a thread from the list. */
542static struct thread *
543thread_list_delete (struct thread_list *list, struct thread *thread)
544{
545 if (thread->next)
546 thread->next->prev = thread->prev;
547 else
548 list->tail = thread->prev;
549 if (thread->prev)
550 thread->prev->next = thread->next;
551 else
552 list->head = thread->next;
553 thread->next = thread->prev = NULL;
554 list->count--;
555 return thread;
556}
557
558/* Move thread to unuse list. */
559static void
560thread_add_unuse (struct thread_master *m, struct thread *thread)
561{
a48b4e6d 562 assert (m != NULL && thread != NULL);
718e3744 563 assert (thread->next == NULL);
564 assert (thread->prev == NULL);
565 assert (thread->type == THREAD_UNUSED);
566 thread_list_add (&m->unuse, thread);
9d11a19e 567 /* XXX: Should we deallocate funcname here? */
718e3744 568}
569
570/* Free all unused thread. */
571static void
572thread_list_free (struct thread_master *m, struct thread_list *list)
573{
574 struct thread *t;
575 struct thread *next;
576
577 for (t = list->head; t; t = next)
578 {
579 next = t->next;
228da428
CC
580 if (t->funcname)
581 XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);
718e3744 582 XFREE (MTYPE_THREAD, t);
583 list->count--;
584 m->alloc--;
585 }
586}
587
588/* Stop thread scheduler. */
589void
590thread_master_free (struct thread_master *m)
591{
592 thread_list_free (m, &m->read);
593 thread_list_free (m, &m->write);
594 thread_list_free (m, &m->timer);
595 thread_list_free (m, &m->event);
596 thread_list_free (m, &m->ready);
597 thread_list_free (m, &m->unuse);
a48b4e6d 598 thread_list_free (m, &m->background);
599
718e3744 600 XFREE (MTYPE_THREAD_MASTER, m);
228da428
CC
601
602 if (cpu_record)
603 {
604 hash_clean (cpu_record, cpu_record_hash_free);
605 hash_free (cpu_record);
606 cpu_record = NULL;
607 }
718e3744 608}
609
8cc4198f 610/* Thread list is empty or not. */
f63f06da 611static int
8cc4198f 612thread_empty (struct thread_list *list)
613{
614 return list->head ? 0 : 1;
615}
616
718e3744 617/* Delete top of the list and return it. */
618static struct thread *
619thread_trim_head (struct thread_list *list)
620{
8cc4198f 621 if (!thread_empty (list))
718e3744 622 return thread_list_delete (list, list->head);
623 return NULL;
624}
625
718e3744 626/* Return remain time in second. */
627unsigned long
628thread_timer_remain_second (struct thread *thread)
629{
db9c0df9
PJ
630 quagga_get_relative (NULL);
631
632 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
633 return thread->u.sands.tv_sec - relative_time.tv_sec;
718e3744 634 else
635 return 0;
636}
637
e04ab74d 638/* Trim blankspace and "()"s */
639static char *
8c328f11 640strip_funcname (const char *funcname)
e04ab74d 641{
642 char buff[100];
643 char tmp, *ret, *e, *b = buff;
644
645 strncpy(buff, funcname, sizeof(buff));
646 buff[ sizeof(buff) -1] = '\0';
647 e = buff +strlen(buff) -1;
648
649 /* Wont work for funcname == "Word (explanation)" */
650
651 while (*b == ' ' || *b == '(')
652 ++b;
653 while (*e == ' ' || *e == ')')
654 --e;
655 e++;
656
657 tmp = *e;
658 *e = '\0';
9d11a19e 659 ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b);
e04ab74d 660 *e = tmp;
661
662 return ret;
663}
664
718e3744 665/* Get new thread. */
666static struct thread *
667thread_get (struct thread_master *m, u_char type,
8c328f11 668 int (*func) (struct thread *), void *arg, const char* funcname)
718e3744 669{
670 struct thread *thread;
671
8cc4198f 672 if (!thread_empty (&m->unuse))
2946f65b 673 {
674 thread = thread_trim_head (&m->unuse);
675 if (thread->funcname)
9d11a19e 676 XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);
2946f65b 677 }
718e3744 678 else
679 {
680 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
681 m->alloc++;
682 }
683 thread->type = type;
e04ab74d 684 thread->add_type = type;
718e3744 685 thread->master = m;
686 thread->func = func;
687 thread->arg = arg;
688
e04ab74d 689 thread->funcname = strip_funcname(funcname);
690
718e3744 691 return thread;
692}
693
694/* Add new read thread. */
695struct thread *
e04ab74d 696funcname_thread_add_read (struct thread_master *m,
8c328f11 697 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
718e3744 698{
699 struct thread *thread;
700
701 assert (m != NULL);
702
703 if (FD_ISSET (fd, &m->readfd))
704 {
705 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
706 return NULL;
707 }
708
e04ab74d 709 thread = thread_get (m, THREAD_READ, func, arg, funcname);
718e3744 710 FD_SET (fd, &m->readfd);
711 thread->u.fd = fd;
712 thread_list_add (&m->read, thread);
713
714 return thread;
715}
716
717/* Add new write thread. */
718struct thread *
e04ab74d 719funcname_thread_add_write (struct thread_master *m,
8c328f11 720 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
718e3744 721{
722 struct thread *thread;
723
724 assert (m != NULL);
725
726 if (FD_ISSET (fd, &m->writefd))
727 {
728 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
729 return NULL;
730 }
731
e04ab74d 732 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
718e3744 733 FD_SET (fd, &m->writefd);
734 thread->u.fd = fd;
735 thread_list_add (&m->write, thread);
736
737 return thread;
738}
739
98c91ac6 740static struct thread *
741funcname_thread_add_timer_timeval (struct thread_master *m,
742 int (*func) (struct thread *),
a48b4e6d 743 int type,
98c91ac6 744 void *arg,
745 struct timeval *time_relative,
8c328f11 746 const char* funcname)
718e3744 747{
718e3744 748 struct thread *thread;
a48b4e6d 749 struct thread_list *list;
db9c0df9 750 struct timeval alarm_time;
718e3744 751 struct thread *tt;
718e3744 752
753 assert (m != NULL);
754
8b70d0b0 755 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
a48b4e6d 756 assert (time_relative);
757
8b70d0b0 758 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
a48b4e6d 759 thread = thread_get (m, type, func, arg, funcname);
718e3744 760
761 /* Do we need jitter here? */
b8192765 762 quagga_get_relative (NULL);
db9c0df9
PJ
763 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
764 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
8b70d0b0 765 thread->u.sands = timeval_adjust(alarm_time);
718e3744 766
9e867fe6 767 /* Sort by timeval. */
a48b4e6d 768 for (tt = list->head; tt; tt = tt->next)
9e867fe6 769 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
770 break;
771
772 if (tt)
a48b4e6d 773 thread_list_add_before (list, tt, thread);
9e867fe6 774 else
a48b4e6d 775 thread_list_add (list, thread);
9e867fe6 776
777 return thread;
778}
779
98c91ac6 780
781/* Add timer event thread. */
9e867fe6 782struct thread *
98c91ac6 783funcname_thread_add_timer (struct thread_master *m,
784 int (*func) (struct thread *),
8c328f11 785 void *arg, long timer, const char* funcname)
9e867fe6 786{
98c91ac6 787 struct timeval trel;
9e867fe6 788
789 assert (m != NULL);
790
9076fbd3 791 trel.tv_sec = timer;
98c91ac6 792 trel.tv_usec = 0;
9e867fe6 793
a48b4e6d 794 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
795 &trel, funcname);
98c91ac6 796}
9e867fe6 797
98c91ac6 798/* Add timer event thread with "millisecond" resolution */
799struct thread *
800funcname_thread_add_timer_msec (struct thread_master *m,
801 int (*func) (struct thread *),
8c328f11 802 void *arg, long timer, const char* funcname)
98c91ac6 803{
804 struct timeval trel;
9e867fe6 805
98c91ac6 806 assert (m != NULL);
718e3744 807
af04bd7c 808 trel.tv_sec = timer / 1000;
809 trel.tv_usec = 1000*(timer % 1000);
98c91ac6 810
a48b4e6d 811 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
812 arg, &trel, funcname);
813}
814
815/* Add a background thread, with an optional millisec delay */
816struct thread *
817funcname_thread_add_background (struct thread_master *m,
818 int (*func) (struct thread *),
819 void *arg, long delay,
820 const char *funcname)
821{
822 struct timeval trel;
823
824 assert (m != NULL);
825
826 if (delay)
827 {
828 trel.tv_sec = delay / 1000;
829 trel.tv_usec = 1000*(delay % 1000);
830 }
831 else
832 {
833 trel.tv_sec = 0;
834 trel.tv_usec = 0;
835 }
836
837 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
838 arg, &trel, funcname);
718e3744 839}
840
841/* Add simple event thread. */
842struct thread *
e04ab74d 843funcname_thread_add_event (struct thread_master *m,
8c328f11 844 int (*func) (struct thread *), void *arg, int val, const char* funcname)
718e3744 845{
846 struct thread *thread;
847
848 assert (m != NULL);
849
e04ab74d 850 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
718e3744 851 thread->u.val = val;
852 thread_list_add (&m->event, thread);
853
854 return thread;
855}
856
857/* Cancel thread from scheduler. */
858void
859thread_cancel (struct thread *thread)
860{
a48b4e6d 861 struct thread_list *list;
862
718e3744 863 switch (thread->type)
864 {
865 case THREAD_READ:
866 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
867 FD_CLR (thread->u.fd, &thread->master->readfd);
a48b4e6d 868 list = &thread->master->read;
718e3744 869 break;
870 case THREAD_WRITE:
871 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
872 FD_CLR (thread->u.fd, &thread->master->writefd);
a48b4e6d 873 list = &thread->master->write;
718e3744 874 break;
875 case THREAD_TIMER:
a48b4e6d 876 list = &thread->master->timer;
718e3744 877 break;
878 case THREAD_EVENT:
a48b4e6d 879 list = &thread->master->event;
718e3744 880 break;
881 case THREAD_READY:
a48b4e6d 882 list = &thread->master->ready;
718e3744 883 break;
a48b4e6d 884 case THREAD_BACKGROUND:
885 list = &thread->master->background;
8b70d0b0 886 break;
718e3744 887 default:
a48b4e6d 888 return;
718e3744 889 break;
890 }
a48b4e6d 891 thread_list_delete (list, thread);
718e3744 892 thread->type = THREAD_UNUSED;
893 thread_add_unuse (thread->master, thread);
894}
895
896/* Delete all events which has argument value arg. */
dc81807a 897unsigned int
718e3744 898thread_cancel_event (struct thread_master *m, void *arg)
899{
dc81807a 900 unsigned int ret = 0;
718e3744 901 struct thread *thread;
902
903 thread = m->event.head;
904 while (thread)
905 {
906 struct thread *t;
907
908 t = thread;
909 thread = t->next;
910
911 if (t->arg == arg)
a48b4e6d 912 {
dc81807a 913 ret++;
a48b4e6d 914 thread_list_delete (&m->event, t);
915 t->type = THREAD_UNUSED;
916 thread_add_unuse (m, t);
917 }
718e3744 918 }
dc81807a 919 return ret;
718e3744 920}
921
a48b4e6d 922static struct timeval *
923thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
718e3744 924{
8cc4198f 925 if (!thread_empty (tlist))
718e3744 926 {
db9c0df9 927 *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
718e3744 928 return timer_val;
929 }
930 return NULL;
931}
718e3744 932
8cc4198f 933static struct thread *
718e3744 934thread_run (struct thread_master *m, struct thread *thread,
935 struct thread *fetch)
936{
937 *fetch = *thread;
938 thread->type = THREAD_UNUSED;
228da428 939 thread->funcname = NULL; /* thread_call will free fetch's copied pointer */
718e3744 940 thread_add_unuse (m, thread);
941 return fetch;
942}
943
a48b4e6d 944static int
945thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
718e3744 946{
947 struct thread *thread;
948 struct thread *next;
949 int ready = 0;
a48b4e6d 950
951 assert (list);
952
718e3744 953 for (thread = list->head; thread; thread = next)
954 {
955 next = thread->next;
956
957 if (FD_ISSET (THREAD_FD (thread), fdset))
a48b4e6d 958 {
959 assert (FD_ISSET (THREAD_FD (thread), mfdset));
960 FD_CLR(THREAD_FD (thread), mfdset);
961 thread_list_delete (list, thread);
962 thread_list_add (&thread->master->ready, thread);
963 thread->type = THREAD_READY;
964 ready++;
965 }
718e3744 966 }
967 return ready;
968}
969
8b70d0b0 970/* Add all timers that have popped to the ready list. */
a48b4e6d 971static unsigned int
972thread_timer_process (struct thread_list *list, struct timeval *timenow)
973{
974 struct thread *thread;
b5043aab 975 struct thread *next;
a48b4e6d 976 unsigned int ready = 0;
977
b5043aab 978 for (thread = list->head; thread; thread = next)
8b70d0b0 979 {
b5043aab 980 next = thread->next;
8b70d0b0 981 if (timeval_cmp (*timenow, thread->u.sands) < 0)
982 return ready;
983 thread_list_delete (list, thread);
984 thread->type = THREAD_READY;
985 thread_list_add (&thread->master->ready, thread);
986 ready++;
987 }
a48b4e6d 988 return ready;
989}
990
2613abe6
PJ
991/* process a list en masse, e.g. for event thread lists */
992static unsigned int
993thread_process (struct thread_list *list)
994{
995 struct thread *thread;
b5043aab 996 struct thread *next;
2613abe6
PJ
997 unsigned int ready = 0;
998
b5043aab 999 for (thread = list->head; thread; thread = next)
2613abe6 1000 {
b5043aab 1001 next = thread->next;
2613abe6
PJ
1002 thread_list_delete (list, thread);
1003 thread->type = THREAD_READY;
1004 thread_list_add (&thread->master->ready, thread);
1005 ready++;
1006 }
1007 return ready;
1008}
1009
1010
718e3744 1011/* Fetch next ready thread. */
1012struct thread *
1013thread_fetch (struct thread_master *m, struct thread *fetch)
1014{
718e3744 1015 struct thread *thread;
1016 fd_set readfd;
1017 fd_set writefd;
1018 fd_set exceptfd;
2613abe6 1019 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
a48b4e6d 1020 struct timeval timer_val_bg;
2613abe6 1021 struct timeval *timer_wait = &timer_val;
a48b4e6d 1022 struct timeval *timer_wait_bg;
718e3744 1023
1024 while (1)
1025 {
a48b4e6d 1026 int num = 0;
a48b4e6d 1027
2613abe6 1028 /* Signals pre-empt everything */
05c447dd 1029 quagga_sigevent_process ();
1030
2613abe6
PJ
1031 /* Drain the ready queue of already scheduled jobs, before scheduling
1032 * more.
a48b4e6d 1033 */
718e3744 1034 if ((thread = thread_trim_head (&m->ready)) != NULL)
05c447dd 1035 return thread_run (m, thread, fetch);
a48b4e6d 1036
2613abe6
PJ
1037 /* To be fair to all kinds of threads, and avoid starvation, we
1038 * need to be careful to consider all thread types for scheduling
1039 * in each quanta. I.e. we should not return early from here on.
1040 */
1041
1042 /* Normal event are the next highest priority. */
1043 thread_process (&m->event);
1044
718e3744 1045 /* Structure copy. */
1046 readfd = m->readfd;
1047 writefd = m->writefd;
1048 exceptfd = m->exceptfd;
a48b4e6d 1049
1050 /* Calculate select wait timer if nothing else to do */
2613abe6
PJ
1051 if (m->ready.count == 0)
1052 {
1053 quagga_get_relative (NULL);
1054 timer_wait = thread_timer_wait (&m->timer, &timer_val);
1055 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
1056
1057 if (timer_wait_bg &&
1058 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1059 timer_wait = timer_wait_bg;
1060 }
a48b4e6d 1061
718e3744 1062 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
a48b4e6d 1063
1064 /* Signals should get quick treatment */
718e3744 1065 if (num < 0)
05c447dd 1066 {
1067 if (errno == EINTR)
a48b4e6d 1068 continue; /* signal received - process it */
6099b3b5 1069 zlog_warn ("select() error: %s", safe_strerror (errno));
05c447dd 1070 return NULL;
1071 }
8b70d0b0 1072
1073 /* Check foreground timers. Historically, they have had higher
1074 priority than I/O threads, so let's push them onto the ready
1075 list in front of the I/O threads. */
db9c0df9
PJ
1076 quagga_get_relative (NULL);
1077 thread_timer_process (&m->timer, &relative_time);
a48b4e6d 1078
1079 /* Got IO, process it */
1080 if (num > 0)
1081 {
1082 /* Normal priority read thead. */
8b70d0b0 1083 thread_process_fd (&m->read, &readfd, &m->readfd);
a48b4e6d 1084 /* Write thead. */
8b70d0b0 1085 thread_process_fd (&m->write, &writefd, &m->writefd);
a48b4e6d 1086 }
8b70d0b0 1087
1088#if 0
1089 /* If any threads were made ready above (I/O or foreground timer),
1090 perhaps we should avoid adding background timers to the ready
1091 list at this time. If this is code is uncommented, then background
1092 timer threads will not run unless there is nothing else to do. */
1093 if ((thread = thread_trim_head (&m->ready)) != NULL)
1094 return thread_run (m, thread, fetch);
1095#endif
1096
a48b4e6d 1097 /* Background timer/events, lowest priority */
db9c0df9 1098 thread_timer_process (&m->background, &relative_time);
a48b4e6d 1099
8b70d0b0 1100 if ((thread = thread_trim_head (&m->ready)) != NULL)
05c447dd 1101 return thread_run (m, thread, fetch);
718e3744 1102 }
1103}
1104
924b9229 1105unsigned long
8b70d0b0 1106thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
718e3744 1107{
718e3744 1108#ifdef HAVE_RUSAGE
1109 /* This is 'user + sys' time. */
8b70d0b0 1110 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1111 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
718e3744 1112#else
8b70d0b0 1113 *cputime = 0;
718e3744 1114#endif /* HAVE_RUSAGE */
8b70d0b0 1115 return timeval_elapsed (now->real, start->real);
1116}
1117
1118/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1119 Note: we are using real (wall clock) time for this calculation.
1120 It could be argued that CPU time may make more sense in certain
1121 contexts. The things to consider are whether the thread may have
1122 blocked (in which case wall time increases, but CPU time does not),
1123 or whether the system is heavily loaded with other processes competing
1124 for CPU time. On balance, wall clock time seems to make sense.
1125 Plus it has the added benefit that gettimeofday should be faster
1126 than calling getrusage. */
718e3744 1127int
1128thread_should_yield (struct thread *thread)
1129{
db9c0df9
PJ
1130 quagga_get_relative (NULL);
1131 return (timeval_elapsed(relative_time, thread->ru.real) >
8b70d0b0 1132 THREAD_YIELD_TIME_SLOT);
718e3744 1133}
1134
db9c0df9
PJ
1135void
1136thread_getrusage (RUSAGE_T *r)
1137{
1138 quagga_get_relative (NULL);
1139#ifdef HAVE_RUSAGE
1140 getrusage(RUSAGE_SELF, &(r->cpu));
1141#endif
1142 r->real = relative_time;
1143
1144#ifdef HAVE_CLOCK_MONOTONIC
1145 /* quagga_get_relative() only updates recent_time if gettimeofday
1146 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1147 * and guarantee to update it before threads are run...
1148 */
1149 quagga_gettimeofday(&recent_time);
1150#endif /* HAVE_CLOCK_MONOTONIC */
1151}
1152
718e3744 1153/* We check thread consumed time. If the system has getrusage, we'll
8b70d0b0 1154 use that to get in-depth stats on the performance of the thread in addition
1155 to wall clock time stats from gettimeofday. */
718e3744 1156void
1157thread_call (struct thread *thread)
1158{
8b70d0b0 1159 unsigned long realtime, cputime;
718e3744 1160 RUSAGE_T ru;
cc8b13a0
PJ
1161
1162 /* Cache a pointer to the relevant cpu history thread, if the thread
1163 * does not have it yet.
1164 *
1165 * Callers submitting 'dummy threads' hence must take care that
1166 * thread->cpu is NULL
1167 */
1168 if (!thread->hist)
1169 {
1170 struct cpu_thread_history tmp;
1171
1172 tmp.func = thread->func;
1173 tmp.funcname = thread->funcname;
1174
1175 thread->hist = hash_get (cpu_record, &tmp,
1176 (void * (*) (void *))cpu_record_hash_alloc);
1177 }
718e3744 1178
1179 GETRUSAGE (&thread->ru);
1180
1181 (*thread->func) (thread);
1182
1183 GETRUSAGE (&ru);
1184
8b70d0b0 1185 realtime = thread_consumed_time (&ru, &thread->ru, &cputime);
cc8b13a0
PJ
1186 thread->hist->real.total += realtime;
1187 if (thread->hist->real.max < realtime)
1188 thread->hist->real.max = realtime;
8b70d0b0 1189#ifdef HAVE_RUSAGE
cc8b13a0
PJ
1190 thread->hist->cpu.total += cputime;
1191 if (thread->hist->cpu.max < cputime)
1192 thread->hist->cpu.max = cputime;
8b70d0b0 1193#endif
e04ab74d 1194
cc8b13a0
PJ
1195 ++(thread->hist->total_calls);
1196 thread->hist->types |= (1 << thread->add_type);
718e3744 1197
924b9229 1198#ifdef CONSUMED_TIME_CHECK
8b70d0b0 1199 if (realtime > CONSUMED_TIME_CHECK)
718e3744 1200 {
1201 /*
1202 * We have a CPU Hog on our hands.
1203 * Whinge about it now, so we're aware this is yet another task
1204 * to fix.
1205 */
8b70d0b0 1206 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
924b9229 1207 thread->funcname,
1208 (unsigned long) thread->func,
8b70d0b0 1209 realtime/1000, cputime/1000);
718e3744 1210 }
924b9229 1211#endif /* CONSUMED_TIME_CHECK */
228da428
CC
1212
1213 XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname);
718e3744 1214}
1215
1216/* Execute thread */
1217struct thread *
e04ab74d 1218funcname_thread_execute (struct thread_master *m,
718e3744 1219 int (*func)(struct thread *),
1220 void *arg,
e04ab74d 1221 int val,
8c328f11 1222 const char* funcname)
718e3744 1223{
1224 struct thread dummy;
1225
1226 memset (&dummy, 0, sizeof (struct thread));
1227
1228 dummy.type = THREAD_EVENT;
e04ab74d 1229 dummy.add_type = THREAD_EXECUTE;
718e3744 1230 dummy.master = NULL;
1231 dummy.func = func;
1232 dummy.arg = arg;
1233 dummy.u.val = val;
e04ab74d 1234 dummy.funcname = strip_funcname (funcname);
718e3744 1235 thread_call (&dummy);
1236
9d11a19e 1237 XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);
2946f65b 1238
718e3744 1239 return NULL;
1240}