blob: 6341dfd77cb8c9a9f16ab66f1d323c64e3e9f34b [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
paule04ab742003-01-17 23:47:00 +000029#include "hash.h"
30#include "command.h"
paul05c447d2004-07-22 19:14:27 +000031#include "sigevent.h"
Vincent Bernatd6be5fb2012-05-24 09:44:43 +020032
33#if defined HAVE_SNMP && defined SNMP_AGENTX
34#include <net-snmp/net-snmp-config.h>
35#include <net-snmp/net-snmp-includes.h>
36#include <net-snmp/agent/net-snmp-agent-includes.h>
37#include <net-snmp/agent/snmp_vars.h>
38
39extern int agentx_enabled;
40#endif
41
paule04ab742003-01-17 23:47:00 +000042
Paul Jakmadb9c0df2006-08-27 06:44:02 +000043/* Recent absolute time of day */
ajs8b70d0b2005-04-28 01:31:13 +000044struct timeval recent_time;
Paul Jakmadb9c0df2006-08-27 06:44:02 +000045static struct timeval last_recent_time;
46/* Relative time, since startup */
47static struct timeval relative_time;
48static struct timeval relative_time_base;
49/* init flag */
50static unsigned short timers_inited;
51
paule04ab742003-01-17 23:47:00 +000052static struct hash *cpu_record = NULL;
paul718e3742002-12-13 20:15:29 +000053
54/* Struct timeval's tv_usec one second value. */
55#define TIMER_SECOND_MICRO 1000000L
56
ajs8b70d0b2005-04-28 01:31:13 +000057/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
58 And change negative values to 0. */
paula48b4e62005-04-22 00:43:47 +000059static struct timeval
paul718e3742002-12-13 20:15:29 +000060timeval_adjust (struct timeval a)
61{
62 while (a.tv_usec >= TIMER_SECOND_MICRO)
63 {
64 a.tv_usec -= TIMER_SECOND_MICRO;
65 a.tv_sec++;
66 }
67
68 while (a.tv_usec < 0)
69 {
70 a.tv_usec += TIMER_SECOND_MICRO;
71 a.tv_sec--;
72 }
73
74 if (a.tv_sec < 0)
ajs8b70d0b2005-04-28 01:31:13 +000075 /* Change negative timeouts to 0. */
76 a.tv_sec = a.tv_usec = 0;
paul718e3742002-12-13 20:15:29 +000077
78 return a;
79}
80
81static struct timeval
82timeval_subtract (struct timeval a, struct timeval b)
83{
84 struct timeval ret;
85
86 ret.tv_usec = a.tv_usec - b.tv_usec;
87 ret.tv_sec = a.tv_sec - b.tv_sec;
88
89 return timeval_adjust (ret);
90}
91
ajs8b70d0b2005-04-28 01:31:13 +000092static long
paul718e3742002-12-13 20:15:29 +000093timeval_cmp (struct timeval a, struct timeval b)
94{
95 return (a.tv_sec == b.tv_sec
96 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
97}
98
99static unsigned long
100timeval_elapsed (struct timeval a, struct timeval b)
101{
102 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
103 + (a.tv_usec - b.tv_usec));
104}
105
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000106#ifndef HAVE_CLOCK_MONOTONIC
107static void
108quagga_gettimeofday_relative_adjust (void)
109{
110 struct timeval diff;
111 if (timeval_cmp (recent_time, last_recent_time) < 0)
112 {
113 relative_time.tv_sec++;
114 relative_time.tv_usec = 0;
115 }
116 else
117 {
118 diff = timeval_subtract (recent_time, last_recent_time);
119 relative_time.tv_sec += diff.tv_sec;
120 relative_time.tv_usec += diff.tv_usec;
121 relative_time = timeval_adjust (relative_time);
122 }
123 last_recent_time = recent_time;
124}
125#endif /* !HAVE_CLOCK_MONOTONIC */
126
127/* gettimeofday wrapper, to keep recent_time updated */
128static int
129quagga_gettimeofday (struct timeval *tv)
130{
131 int ret;
132
133 assert (tv);
134
135 if (!(ret = gettimeofday (&recent_time, NULL)))
136 {
137 /* init... */
138 if (!timers_inited)
139 {
140 relative_time_base = last_recent_time = recent_time;
141 timers_inited = 1;
142 }
143 /* avoid copy if user passed recent_time pointer.. */
144 if (tv != &recent_time)
145 *tv = recent_time;
146 return 0;
147 }
148 return ret;
149}
150
151static int
152quagga_get_relative (struct timeval *tv)
153{
154 int ret;
155
156#ifdef HAVE_CLOCK_MONOTONIC
157 {
158 struct timespec tp;
159 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
160 {
161 relative_time.tv_sec = tp.tv_sec;
162 relative_time.tv_usec = tp.tv_nsec / 1000;
163 }
164 }
165#else /* !HAVE_CLOCK_MONOTONIC */
166 if (!(ret = quagga_gettimeofday (&recent_time)))
167 quagga_gettimeofday_relative_adjust();
168#endif /* HAVE_CLOCK_MONOTONIC */
169
170 if (tv)
171 *tv = relative_time;
172
173 return ret;
174}
175
176/* Get absolute time stamp, but in terms of the internal timer
177 * Could be wrong, but at least won't go back.
178 */
179static void
180quagga_real_stabilised (struct timeval *tv)
181{
182 *tv = relative_time_base;
183 tv->tv_sec += relative_time.tv_sec;
184 tv->tv_usec += relative_time.tv_usec;
185 *tv = timeval_adjust (*tv);
186}
187
188/* Exported Quagga timestamp function.
189 * Modelled on POSIX clock_gettime.
190 */
191int
192quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
193{
194 switch (clkid)
195 {
196 case QUAGGA_CLK_REALTIME:
197 return quagga_gettimeofday (tv);
198 case QUAGGA_CLK_MONOTONIC:
199 return quagga_get_relative (tv);
200 case QUAGGA_CLK_REALTIME_STABILISED:
201 quagga_real_stabilised (tv);
202 return 0;
203 default:
204 errno = EINVAL;
205 return -1;
206 }
207}
208
209/* time_t value in terms of stabilised absolute time.
210 * replacement for POSIX time()
211 */
212time_t
213quagga_time (time_t *t)
214{
215 struct timeval tv;
216 quagga_real_stabilised (&tv);
217 if (t)
218 *t = tv.tv_sec;
219 return tv.tv_sec;
220}
221
222/* Public export of recent_relative_time by value */
223struct timeval
224recent_relative_time (void)
225{
226 return relative_time;
227}
228
paula48b4e62005-04-22 00:43:47 +0000229static unsigned int
paule04ab742003-01-17 23:47:00 +0000230cpu_record_hash_key (struct cpu_thread_history *a)
231{
paul8cc41982005-05-06 21:25:49 +0000232 return (uintptr_t) a->func;
paule04ab742003-01-17 23:47:00 +0000233}
234
235static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100236cpu_record_hash_cmp (const struct cpu_thread_history *a,
237 const struct cpu_thread_history *b)
paule04ab742003-01-17 23:47:00 +0000238{
239 return a->func == b->func;
240}
241
paul8cc41982005-05-06 21:25:49 +0000242static void *
paule04ab742003-01-17 23:47:00 +0000243cpu_record_hash_alloc (struct cpu_thread_history *a)
244{
245 struct cpu_thread_history *new;
paul039b9572004-10-31 16:43:17 +0000246 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
paule04ab742003-01-17 23:47:00 +0000247 new->func = a->func;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000248 strcpy(new->funcname, a->funcname);
paule04ab742003-01-17 23:47:00 +0000249 return new;
250}
251
Chris Caputo228da422009-07-18 05:44:03 +0000252static void
253cpu_record_hash_free (void *a)
254{
255 struct cpu_thread_history *hist = a;
256
Chris Caputo228da422009-07-18 05:44:03 +0000257 XFREE (MTYPE_THREAD_STATS, hist);
258}
259
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100260static void
paule04ab742003-01-17 23:47:00 +0000261vty_out_cpu_thread_history(struct vty* vty,
262 struct cpu_thread_history *a)
263{
ajs8b70d0b2005-04-28 01:31:13 +0000264#ifdef HAVE_RUSAGE
265 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
266 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
267 a->cpu.total/a->total_calls, a->cpu.max,
268 a->real.total/a->total_calls, a->real.max);
269#else
270 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
271 a->real.total/1000, a->real.total%1000, a->total_calls,
272 a->real.total/a->total_calls, a->real.max);
273#endif
274 vty_out(vty, " %c%c%c%c%c%c %s%s",
paule04ab742003-01-17 23:47:00 +0000275 a->types & (1 << THREAD_READ) ? 'R':' ',
276 a->types & (1 << THREAD_WRITE) ? 'W':' ',
277 a->types & (1 << THREAD_TIMER) ? 'T':' ',
278 a->types & (1 << THREAD_EVENT) ? 'E':' ',
279 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
paula48b4e62005-04-22 00:43:47 +0000280 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
paule04ab742003-01-17 23:47:00 +0000281 a->funcname, VTY_NEWLINE);
282}
283
284static void
285cpu_record_hash_print(struct hash_backet *bucket,
286 void *args[])
287{
288 struct cpu_thread_history *totals = args[0];
289 struct vty *vty = args[1];
Paul Jakma41b23732009-06-30 16:12:49 +0100290 thread_type *filter = args[2];
paule04ab742003-01-17 23:47:00 +0000291 struct cpu_thread_history *a = bucket->data;
paula48b4e62005-04-22 00:43:47 +0000292
paule04ab742003-01-17 23:47:00 +0000293 a = bucket->data;
294 if ( !(a->types & *filter) )
295 return;
296 vty_out_cpu_thread_history(vty,a);
paule04ab742003-01-17 23:47:00 +0000297 totals->total_calls += a->total_calls;
ajs8b70d0b2005-04-28 01:31:13 +0000298 totals->real.total += a->real.total;
299 if (totals->real.max < a->real.max)
300 totals->real.max = a->real.max;
301#ifdef HAVE_RUSAGE
302 totals->cpu.total += a->cpu.total;
303 if (totals->cpu.max < a->cpu.max)
304 totals->cpu.max = a->cpu.max;
305#endif
paule04ab742003-01-17 23:47:00 +0000306}
307
308static void
Paul Jakma41b23732009-06-30 16:12:49 +0100309cpu_record_print(struct vty *vty, thread_type filter)
paule04ab742003-01-17 23:47:00 +0000310{
311 struct cpu_thread_history tmp;
312 void *args[3] = {&tmp, vty, &filter};
313
314 memset(&tmp, 0, sizeof tmp);
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000315 strcpy(tmp.funcname, "TOTAL");
paule04ab742003-01-17 23:47:00 +0000316 tmp.types = filter;
317
ajs8b70d0b2005-04-28 01:31:13 +0000318#ifdef HAVE_RUSAGE
319 vty_out(vty, "%21s %18s %18s%s",
320 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
321#endif
322 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
323#ifdef HAVE_RUSAGE
324 vty_out(vty, " Avg uSec Max uSecs");
325#endif
326 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
paule04ab742003-01-17 23:47:00 +0000327 hash_iterate(cpu_record,
328 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
329 args);
330
331 if (tmp.total_calls > 0)
332 vty_out_cpu_thread_history(vty, &tmp);
333}
334
335DEFUN(show_thread_cpu,
336 show_thread_cpu_cmd,
337 "show thread cpu [FILTER]",
338 SHOW_STR
339 "Thread information\n"
340 "Thread CPU usage\n"
paula48b4e62005-04-22 00:43:47 +0000341 "Display filter (rwtexb)\n")
paule04ab742003-01-17 23:47:00 +0000342{
343 int i = 0;
Paul Jakma41b23732009-06-30 16:12:49 +0100344 thread_type filter = (thread_type) -1U;
paule04ab742003-01-17 23:47:00 +0000345
346 if (argc > 0)
347 {
348 filter = 0;
349 while (argv[0][i] != '\0')
350 {
351 switch ( argv[0][i] )
352 {
353 case 'r':
354 case 'R':
355 filter |= (1 << THREAD_READ);
356 break;
357 case 'w':
358 case 'W':
359 filter |= (1 << THREAD_WRITE);
360 break;
361 case 't':
362 case 'T':
363 filter |= (1 << THREAD_TIMER);
364 break;
365 case 'e':
366 case 'E':
367 filter |= (1 << THREAD_EVENT);
368 break;
369 case 'x':
370 case 'X':
371 filter |= (1 << THREAD_EXECUTE);
372 break;
paula48b4e62005-04-22 00:43:47 +0000373 case 'b':
374 case 'B':
375 filter |= (1 << THREAD_BACKGROUND);
376 break;
paule04ab742003-01-17 23:47:00 +0000377 default:
378 break;
379 }
380 ++i;
381 }
382 if (filter == 0)
383 {
paula48b4e62005-04-22 00:43:47 +0000384 vty_out(vty, "Invalid filter \"%s\" specified,"
385 " must contain at least one of 'RWTEXB'%s",
paule04ab742003-01-17 23:47:00 +0000386 argv[0], VTY_NEWLINE);
387 return CMD_WARNING;
388 }
389 }
390
391 cpu_record_print(vty, filter);
392 return CMD_SUCCESS;
393}
Paul Jakmae276eb82010-01-09 16:15:00 +0000394
395static void
396cpu_record_hash_clear (struct hash_backet *bucket,
397 void *args)
398{
399 thread_type *filter = args;
400 struct cpu_thread_history *a = bucket->data;
401
402 a = bucket->data;
403 if ( !(a->types & *filter) )
404 return;
405
406 hash_release (cpu_record, bucket->data);
407}
408
409static void
410cpu_record_clear (thread_type filter)
411{
412 thread_type *tmp = &filter;
413 hash_iterate (cpu_record,
414 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
415 tmp);
416}
417
418DEFUN(clear_thread_cpu,
419 clear_thread_cpu_cmd,
420 "clear thread cpu [FILTER]",
421 "Clear stored data\n"
422 "Thread information\n"
423 "Thread CPU usage\n"
424 "Display filter (rwtexb)\n")
425{
426 int i = 0;
427 thread_type filter = (thread_type) -1U;
428
429 if (argc > 0)
430 {
431 filter = 0;
432 while (argv[0][i] != '\0')
433 {
434 switch ( argv[0][i] )
435 {
436 case 'r':
437 case 'R':
438 filter |= (1 << THREAD_READ);
439 break;
440 case 'w':
441 case 'W':
442 filter |= (1 << THREAD_WRITE);
443 break;
444 case 't':
445 case 'T':
446 filter |= (1 << THREAD_TIMER);
447 break;
448 case 'e':
449 case 'E':
450 filter |= (1 << THREAD_EVENT);
451 break;
452 case 'x':
453 case 'X':
454 filter |= (1 << THREAD_EXECUTE);
455 break;
456 case 'b':
457 case 'B':
458 filter |= (1 << THREAD_BACKGROUND);
459 break;
460 default:
461 break;
462 }
463 ++i;
464 }
465 if (filter == 0)
466 {
467 vty_out(vty, "Invalid filter \"%s\" specified,"
468 " must contain at least one of 'RWTEXB'%s",
469 argv[0], VTY_NEWLINE);
470 return CMD_WARNING;
471 }
472 }
473
474 cpu_record_clear (filter);
475 return CMD_SUCCESS;
476}
paule04ab742003-01-17 23:47:00 +0000477
paul718e3742002-12-13 20:15:29 +0000478/* List allocation and head/tail print out. */
479static void
480thread_list_debug (struct thread_list *list)
481{
482 printf ("count [%d] head [%p] tail [%p]\n",
483 list->count, list->head, list->tail);
484}
485
486/* Debug print for thread_master. */
paul8cc41982005-05-06 21:25:49 +0000487static void __attribute__ ((unused))
paul718e3742002-12-13 20:15:29 +0000488thread_master_debug (struct thread_master *m)
489{
490 printf ("-----------\n");
491 printf ("readlist : ");
492 thread_list_debug (&m->read);
493 printf ("writelist : ");
494 thread_list_debug (&m->write);
495 printf ("timerlist : ");
496 thread_list_debug (&m->timer);
497 printf ("eventlist : ");
498 thread_list_debug (&m->event);
499 printf ("unuselist : ");
500 thread_list_debug (&m->unuse);
paula48b4e62005-04-22 00:43:47 +0000501 printf ("bgndlist : ");
502 thread_list_debug (&m->background);
paul718e3742002-12-13 20:15:29 +0000503 printf ("total alloc: [%ld]\n", m->alloc);
504 printf ("-----------\n");
505}
506
507/* Allocate new thread master. */
508struct thread_master *
509thread_master_create ()
510{
paule04ab742003-01-17 23:47:00 +0000511 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000512 cpu_record
513 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100514 (int (*) (const void *, const void *))cpu_record_hash_cmp);
paula48b4e62005-04-22 00:43:47 +0000515
paul718e3742002-12-13 20:15:29 +0000516 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
517 sizeof (struct thread_master));
518}
519
520/* Add a new thread to the list. */
521static void
522thread_list_add (struct thread_list *list, struct thread *thread)
523{
524 thread->next = NULL;
525 thread->prev = list->tail;
526 if (list->tail)
527 list->tail->next = thread;
528 else
529 list->head = thread;
530 list->tail = thread;
531 list->count++;
532}
533
534/* Add a new thread just before the point. */
535static void
536thread_list_add_before (struct thread_list *list,
537 struct thread *point,
538 struct thread *thread)
539{
540 thread->next = point;
541 thread->prev = point->prev;
542 if (point->prev)
543 point->prev->next = thread;
544 else
545 list->head = thread;
546 point->prev = thread;
547 list->count++;
548}
549
550/* Delete a thread from the list. */
551static struct thread *
552thread_list_delete (struct thread_list *list, struct thread *thread)
553{
554 if (thread->next)
555 thread->next->prev = thread->prev;
556 else
557 list->tail = thread->prev;
558 if (thread->prev)
559 thread->prev->next = thread->next;
560 else
561 list->head = thread->next;
562 thread->next = thread->prev = NULL;
563 list->count--;
564 return thread;
565}
566
567/* Move thread to unuse list. */
568static void
569thread_add_unuse (struct thread_master *m, struct thread *thread)
570{
paula48b4e62005-04-22 00:43:47 +0000571 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000572 assert (thread->next == NULL);
573 assert (thread->prev == NULL);
574 assert (thread->type == THREAD_UNUSED);
575 thread_list_add (&m->unuse, thread);
paul9d11a192004-10-31 16:19:24 +0000576 /* XXX: Should we deallocate funcname here? */
paul718e3742002-12-13 20:15:29 +0000577}
578
579/* Free all unused thread. */
580static void
581thread_list_free (struct thread_master *m, struct thread_list *list)
582{
583 struct thread *t;
584 struct thread *next;
585
586 for (t = list->head; t; t = next)
587 {
588 next = t->next;
589 XFREE (MTYPE_THREAD, t);
590 list->count--;
591 m->alloc--;
592 }
593}
594
595/* Stop thread scheduler. */
596void
597thread_master_free (struct thread_master *m)
598{
599 thread_list_free (m, &m->read);
600 thread_list_free (m, &m->write);
601 thread_list_free (m, &m->timer);
602 thread_list_free (m, &m->event);
603 thread_list_free (m, &m->ready);
604 thread_list_free (m, &m->unuse);
paula48b4e62005-04-22 00:43:47 +0000605 thread_list_free (m, &m->background);
606
paul718e3742002-12-13 20:15:29 +0000607 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000608
609 if (cpu_record)
610 {
611 hash_clean (cpu_record, cpu_record_hash_free);
612 hash_free (cpu_record);
613 cpu_record = NULL;
614 }
paul718e3742002-12-13 20:15:29 +0000615}
616
paul8cc41982005-05-06 21:25:49 +0000617/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100618static int
paul8cc41982005-05-06 21:25:49 +0000619thread_empty (struct thread_list *list)
620{
621 return list->head ? 0 : 1;
622}
623
paul718e3742002-12-13 20:15:29 +0000624/* Delete top of the list and return it. */
625static struct thread *
626thread_trim_head (struct thread_list *list)
627{
paul8cc41982005-05-06 21:25:49 +0000628 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000629 return thread_list_delete (list, list->head);
630 return NULL;
631}
632
paul718e3742002-12-13 20:15:29 +0000633/* Return remain time in second. */
634unsigned long
635thread_timer_remain_second (struct thread *thread)
636{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000637 quagga_get_relative (NULL);
638
639 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
640 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000641 else
642 return 0;
643}
644
paule04ab742003-01-17 23:47:00 +0000645/* Trim blankspace and "()"s */
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000646void
647strip_funcname (char *dest, const char *funcname)
paule04ab742003-01-17 23:47:00 +0000648{
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000649 char buff[FUNCNAME_LEN];
650 char tmp, *e, *b = buff;
paule04ab742003-01-17 23:47:00 +0000651
652 strncpy(buff, funcname, sizeof(buff));
653 buff[ sizeof(buff) -1] = '\0';
654 e = buff +strlen(buff) -1;
655
656 /* Wont work for funcname == "Word (explanation)" */
657
658 while (*b == ' ' || *b == '(')
659 ++b;
660 while (*e == ' ' || *e == ')')
661 --e;
662 e++;
663
664 tmp = *e;
665 *e = '\0';
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000666 strcpy (dest, b);
paule04ab742003-01-17 23:47:00 +0000667 *e = tmp;
paule04ab742003-01-17 23:47:00 +0000668}
669
paul718e3742002-12-13 20:15:29 +0000670/* Get new thread. */
671static struct thread *
672thread_get (struct thread_master *m, u_char type,
hasso8c328f12004-10-05 21:01:23 +0000673 int (*func) (struct thread *), void *arg, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000674{
Jorge Boncompte [DTI2]64018322012-05-07 16:53:13 +0000675 struct thread *thread = thread_trim_head (&m->unuse);
paul718e3742002-12-13 20:15:29 +0000676
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000677 if (! thread)
paul718e3742002-12-13 20:15:29 +0000678 {
679 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
680 m->alloc++;
681 }
682 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000683 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000684 thread->master = m;
685 thread->func = func;
686 thread->arg = arg;
687
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000688 strip_funcname (thread->funcname, funcname);
paule04ab742003-01-17 23:47:00 +0000689
paul718e3742002-12-13 20:15:29 +0000690 return thread;
691}
692
693/* Add new read thread. */
694struct thread *
paule04ab742003-01-17 23:47:00 +0000695funcname_thread_add_read (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000696 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000697{
698 struct thread *thread;
699
700 assert (m != NULL);
701
702 if (FD_ISSET (fd, &m->readfd))
703 {
704 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
705 return NULL;
706 }
707
paule04ab742003-01-17 23:47:00 +0000708 thread = thread_get (m, THREAD_READ, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000709 FD_SET (fd, &m->readfd);
710 thread->u.fd = fd;
711 thread_list_add (&m->read, thread);
712
713 return thread;
714}
715
716/* Add new write thread. */
717struct thread *
paule04ab742003-01-17 23:47:00 +0000718funcname_thread_add_write (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000719 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000720{
721 struct thread *thread;
722
723 assert (m != NULL);
724
725 if (FD_ISSET (fd, &m->writefd))
726 {
727 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
728 return NULL;
729 }
730
paule04ab742003-01-17 23:47:00 +0000731 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000732 FD_SET (fd, &m->writefd);
733 thread->u.fd = fd;
734 thread_list_add (&m->write, thread);
735
736 return thread;
737}
738
paul98c91ac2004-10-05 14:57:50 +0000739static struct thread *
740funcname_thread_add_timer_timeval (struct thread_master *m,
741 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000742 int type,
paul98c91ac2004-10-05 14:57:50 +0000743 void *arg,
744 struct timeval *time_relative,
hasso8c328f12004-10-05 21:01:23 +0000745 const char* funcname)
paul718e3742002-12-13 20:15:29 +0000746{
paul718e3742002-12-13 20:15:29 +0000747 struct thread *thread;
paula48b4e62005-04-22 00:43:47 +0000748 struct thread_list *list;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000749 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000750 struct thread *tt;
paul718e3742002-12-13 20:15:29 +0000751
752 assert (m != NULL);
753
ajs8b70d0b2005-04-28 01:31:13 +0000754 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000755 assert (time_relative);
756
ajs8b70d0b2005-04-28 01:31:13 +0000757 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
paula48b4e62005-04-22 00:43:47 +0000758 thread = thread_get (m, type, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000759
760 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100761 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000762 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
763 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000764 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000765
766 /* Sort by timeval. */
paula48b4e62005-04-22 00:43:47 +0000767 for (tt = list->head; tt; tt = tt->next)
paul718e3742002-12-13 20:15:29 +0000768 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
769 break;
770
771 if (tt)
paula48b4e62005-04-22 00:43:47 +0000772 thread_list_add_before (list, tt, thread);
paul718e3742002-12-13 20:15:29 +0000773 else
paula48b4e62005-04-22 00:43:47 +0000774 thread_list_add (list, thread);
paul718e3742002-12-13 20:15:29 +0000775
776 return thread;
777}
778
paul98c91ac2004-10-05 14:57:50 +0000779
780/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000781struct thread *
paul98c91ac2004-10-05 14:57:50 +0000782funcname_thread_add_timer (struct thread_master *m,
783 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000784 void *arg, long timer, const char* funcname)
jardin9e867fe2003-12-23 08:56:18 +0000785{
paul98c91ac2004-10-05 14:57:50 +0000786 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000787
788 assert (m != NULL);
789
paul9076fbd2004-10-11 09:40:58 +0000790 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000791 trel.tv_usec = 0;
792
paula48b4e62005-04-22 00:43:47 +0000793 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
794 &trel, funcname);
paul98c91ac2004-10-05 14:57:50 +0000795}
796
797/* Add timer event thread with "millisecond" resolution */
798struct thread *
799funcname_thread_add_timer_msec (struct thread_master *m,
800 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000801 void *arg, long timer, const char* funcname)
paul98c91ac2004-10-05 14:57:50 +0000802{
803 struct timeval trel;
804
805 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000806
ajsaf04bd72004-12-28 17:00:12 +0000807 trel.tv_sec = timer / 1000;
808 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000809
paula48b4e62005-04-22 00:43:47 +0000810 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
811 arg, &trel, funcname);
812}
813
814/* Add a background thread, with an optional millisec delay */
815struct thread *
816funcname_thread_add_background (struct thread_master *m,
817 int (*func) (struct thread *),
818 void *arg, long delay,
819 const char *funcname)
820{
821 struct timeval trel;
822
823 assert (m != NULL);
824
825 if (delay)
826 {
827 trel.tv_sec = delay / 1000;
828 trel.tv_usec = 1000*(delay % 1000);
829 }
830 else
831 {
832 trel.tv_sec = 0;
833 trel.tv_usec = 0;
834 }
835
836 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
837 arg, &trel, funcname);
jardin9e867fe2003-12-23 08:56:18 +0000838}
839
paul718e3742002-12-13 20:15:29 +0000840/* Add simple event thread. */
841struct thread *
paule04ab742003-01-17 23:47:00 +0000842funcname_thread_add_event (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000843 int (*func) (struct thread *), void *arg, int val, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000844{
845 struct thread *thread;
846
847 assert (m != NULL);
848
paule04ab742003-01-17 23:47:00 +0000849 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000850 thread->u.val = val;
851 thread_list_add (&m->event, thread);
852
853 return thread;
854}
855
856/* Cancel thread from scheduler. */
857void
858thread_cancel (struct thread *thread)
859{
paula48b4e62005-04-22 00:43:47 +0000860 struct thread_list *list;
861
paul718e3742002-12-13 20:15:29 +0000862 switch (thread->type)
863 {
864 case THREAD_READ:
865 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
866 FD_CLR (thread->u.fd, &thread->master->readfd);
paula48b4e62005-04-22 00:43:47 +0000867 list = &thread->master->read;
paul718e3742002-12-13 20:15:29 +0000868 break;
869 case THREAD_WRITE:
870 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
871 FD_CLR (thread->u.fd, &thread->master->writefd);
paula48b4e62005-04-22 00:43:47 +0000872 list = &thread->master->write;
paul718e3742002-12-13 20:15:29 +0000873 break;
874 case THREAD_TIMER:
paula48b4e62005-04-22 00:43:47 +0000875 list = &thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000876 break;
877 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000878 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000879 break;
880 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000881 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000882 break;
paula48b4e62005-04-22 00:43:47 +0000883 case THREAD_BACKGROUND:
884 list = &thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000885 break;
paul718e3742002-12-13 20:15:29 +0000886 default:
paula48b4e62005-04-22 00:43:47 +0000887 return;
paul718e3742002-12-13 20:15:29 +0000888 break;
889 }
paula48b4e62005-04-22 00:43:47 +0000890 thread_list_delete (list, thread);
paul718e3742002-12-13 20:15:29 +0000891 thread->type = THREAD_UNUSED;
892 thread_add_unuse (thread->master, thread);
893}
894
895/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +0000896unsigned int
paul718e3742002-12-13 20:15:29 +0000897thread_cancel_event (struct thread_master *m, void *arg)
898{
pauldc818072005-05-19 01:30:53 +0000899 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +0000900 struct thread *thread;
901
902 thread = m->event.head;
903 while (thread)
904 {
905 struct thread *t;
906
907 t = thread;
908 thread = t->next;
909
910 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +0000911 {
pauldc818072005-05-19 01:30:53 +0000912 ret++;
paula48b4e62005-04-22 00:43:47 +0000913 thread_list_delete (&m->event, t);
914 t->type = THREAD_UNUSED;
915 thread_add_unuse (m, t);
916 }
paul718e3742002-12-13 20:15:29 +0000917 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +0000918
919 /* thread can be on the ready list too */
920 thread = m->ready.head;
921 while (thread)
922 {
923 struct thread *t;
924
925 t = thread;
926 thread = t->next;
927
928 if (t->arg == arg)
929 {
930 ret++;
931 thread_list_delete (&m->ready, t);
932 t->type = THREAD_UNUSED;
933 thread_add_unuse (m, t);
934 }
935 }
pauldc818072005-05-19 01:30:53 +0000936 return ret;
paul718e3742002-12-13 20:15:29 +0000937}
938
paula48b4e62005-04-22 00:43:47 +0000939static struct timeval *
940thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +0000941{
paul8cc41982005-05-06 21:25:49 +0000942 if (!thread_empty (tlist))
paul718e3742002-12-13 20:15:29 +0000943 {
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000944 *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +0000945 return timer_val;
946 }
947 return NULL;
948}
paul718e3742002-12-13 20:15:29 +0000949
paul8cc41982005-05-06 21:25:49 +0000950static struct thread *
paul718e3742002-12-13 20:15:29 +0000951thread_run (struct thread_master *m, struct thread *thread,
952 struct thread *fetch)
953{
954 *fetch = *thread;
955 thread->type = THREAD_UNUSED;
956 thread_add_unuse (m, thread);
957 return fetch;
958}
959
paula48b4e62005-04-22 00:43:47 +0000960static int
961thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
paul718e3742002-12-13 20:15:29 +0000962{
963 struct thread *thread;
964 struct thread *next;
965 int ready = 0;
paula48b4e62005-04-22 00:43:47 +0000966
967 assert (list);
968
paul718e3742002-12-13 20:15:29 +0000969 for (thread = list->head; thread; thread = next)
970 {
971 next = thread->next;
972
973 if (FD_ISSET (THREAD_FD (thread), fdset))
paula48b4e62005-04-22 00:43:47 +0000974 {
975 assert (FD_ISSET (THREAD_FD (thread), mfdset));
976 FD_CLR(THREAD_FD (thread), mfdset);
977 thread_list_delete (list, thread);
978 thread_list_add (&thread->master->ready, thread);
979 thread->type = THREAD_READY;
980 ready++;
981 }
paul718e3742002-12-13 20:15:29 +0000982 }
983 return ready;
984}
985
ajs8b70d0b2005-04-28 01:31:13 +0000986/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +0000987static unsigned int
988thread_timer_process (struct thread_list *list, struct timeval *timenow)
989{
990 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +0000991 struct thread *next;
paula48b4e62005-04-22 00:43:47 +0000992 unsigned int ready = 0;
993
Paul Jakmab5043aa2012-02-28 18:32:56 +0000994 for (thread = list->head; thread; thread = next)
ajs8b70d0b2005-04-28 01:31:13 +0000995 {
Paul Jakmab5043aa2012-02-28 18:32:56 +0000996 next = thread->next;
ajs8b70d0b2005-04-28 01:31:13 +0000997 if (timeval_cmp (*timenow, thread->u.sands) < 0)
998 return ready;
999 thread_list_delete (list, thread);
1000 thread->type = THREAD_READY;
1001 thread_list_add (&thread->master->ready, thread);
1002 ready++;
1003 }
paula48b4e62005-04-22 00:43:47 +00001004 return ready;
1005}
1006
Paul Jakma2613abe2010-01-11 16:33:07 +00001007/* process a list en masse, e.g. for event thread lists */
1008static unsigned int
1009thread_process (struct thread_list *list)
1010{
1011 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001012 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001013 unsigned int ready = 0;
1014
Paul Jakmab5043aa2012-02-28 18:32:56 +00001015 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001016 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001017 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001018 thread_list_delete (list, thread);
1019 thread->type = THREAD_READY;
1020 thread_list_add (&thread->master->ready, thread);
1021 ready++;
1022 }
1023 return ready;
1024}
1025
1026
paul718e3742002-12-13 20:15:29 +00001027/* Fetch next ready thread. */
1028struct thread *
1029thread_fetch (struct thread_master *m, struct thread *fetch)
1030{
paul718e3742002-12-13 20:15:29 +00001031 struct thread *thread;
1032 fd_set readfd;
1033 fd_set writefd;
1034 fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001035 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001036 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001037 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001038 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001039
1040 while (1)
1041 {
paula48b4e62005-04-22 00:43:47 +00001042 int num = 0;
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001043#if defined HAVE_SNMP && defined SNMP_AGENTX
1044 struct timeval snmp_timer_wait;
1045 int snmpblock = 0;
1046 int fdsetsize;
1047#endif
paula48b4e62005-04-22 00:43:47 +00001048
Paul Jakma2613abe2010-01-11 16:33:07 +00001049 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001050 quagga_sigevent_process ();
1051
Paul Jakma2613abe2010-01-11 16:33:07 +00001052 /* Drain the ready queue of already scheduled jobs, before scheduling
1053 * more.
paula48b4e62005-04-22 00:43:47 +00001054 */
paul718e3742002-12-13 20:15:29 +00001055 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001056 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001057
Paul Jakma2613abe2010-01-11 16:33:07 +00001058 /* To be fair to all kinds of threads, and avoid starvation, we
1059 * need to be careful to consider all thread types for scheduling
1060 * in each quanta. I.e. we should not return early from here on.
1061 */
1062
1063 /* Normal event are the next highest priority. */
1064 thread_process (&m->event);
1065
paul718e3742002-12-13 20:15:29 +00001066 /* Structure copy. */
1067 readfd = m->readfd;
1068 writefd = m->writefd;
1069 exceptfd = m->exceptfd;
paula48b4e62005-04-22 00:43:47 +00001070
1071 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001072 if (m->ready.count == 0)
1073 {
1074 quagga_get_relative (NULL);
1075 timer_wait = thread_timer_wait (&m->timer, &timer_val);
1076 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
1077
1078 if (timer_wait_bg &&
1079 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1080 timer_wait = timer_wait_bg;
1081 }
paula48b4e62005-04-22 00:43:47 +00001082
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001083#if defined HAVE_SNMP && defined SNMP_AGENTX
1084 /* When SNMP is enabled, we may have to select() on additional
1085 FD. snmp_select_info() will add them to `readfd'. The trick
1086 with this function is its last argument. We need to set it to
1087 0 if timer_wait is not NULL and we need to use the provided
1088 new timer only if it is still set to 0. */
1089 if (agentx_enabled)
1090 {
1091 fdsetsize = FD_SETSIZE;
1092 snmpblock = 1;
1093 if (timer_wait)
1094 {
1095 snmpblock = 0;
1096 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
1097 }
1098 snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
1099 if (snmpblock == 0)
1100 timer_wait = &snmp_timer_wait;
1101 }
1102#endif
paul718e3742002-12-13 20:15:29 +00001103 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001104
1105 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001106 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001107 {
1108 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001109 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001110 zlog_warn ("select() error: %s", safe_strerror (errno));
paul05c447d2004-07-22 19:14:27 +00001111 return NULL;
1112 }
ajs8b70d0b2005-04-28 01:31:13 +00001113
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001114#if defined HAVE_SNMP && defined SNMP_AGENTX
1115 if (agentx_enabled)
1116 {
1117 if (num > 0)
1118 snmp_read(&readfd);
1119 else if (num == 0)
1120 {
1121 snmp_timeout();
1122 run_alarms();
1123 }
1124 netsnmp_check_outstanding_agent_requests();
1125 }
1126#endif
1127
ajs8b70d0b2005-04-28 01:31:13 +00001128 /* Check foreground timers. Historically, they have had higher
1129 priority than I/O threads, so let's push them onto the ready
1130 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001131 quagga_get_relative (NULL);
1132 thread_timer_process (&m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001133
1134 /* Got IO, process it */
1135 if (num > 0)
1136 {
1137 /* Normal priority read thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001138 thread_process_fd (&m->read, &readfd, &m->readfd);
paula48b4e62005-04-22 00:43:47 +00001139 /* Write thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001140 thread_process_fd (&m->write, &writefd, &m->writefd);
paula48b4e62005-04-22 00:43:47 +00001141 }
ajs8b70d0b2005-04-28 01:31:13 +00001142
1143#if 0
1144 /* If any threads were made ready above (I/O or foreground timer),
1145 perhaps we should avoid adding background timers to the ready
1146 list at this time. If this is code is uncommented, then background
1147 timer threads will not run unless there is nothing else to do. */
1148 if ((thread = thread_trim_head (&m->ready)) != NULL)
1149 return thread_run (m, thread, fetch);
1150#endif
1151
paula48b4e62005-04-22 00:43:47 +00001152 /* Background timer/events, lowest priority */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001153 thread_timer_process (&m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001154
ajs8b70d0b2005-04-28 01:31:13 +00001155 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001156 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001157 }
1158}
1159
ajs924b9222005-04-16 17:11:24 +00001160unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001161thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001162{
paul718e3742002-12-13 20:15:29 +00001163#ifdef HAVE_RUSAGE
1164 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001165 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1166 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001167#else
ajs8b70d0b2005-04-28 01:31:13 +00001168 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001169#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001170 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001171}
1172
ajs8b70d0b2005-04-28 01:31:13 +00001173/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1174 Note: we are using real (wall clock) time for this calculation.
1175 It could be argued that CPU time may make more sense in certain
1176 contexts. The things to consider are whether the thread may have
1177 blocked (in which case wall time increases, but CPU time does not),
1178 or whether the system is heavily loaded with other processes competing
1179 for CPU time. On balance, wall clock time seems to make sense.
1180 Plus it has the added benefit that gettimeofday should be faster
1181 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001182int
1183thread_should_yield (struct thread *thread)
1184{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001185 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001186 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001187 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001188}
1189
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001190void
1191thread_getrusage (RUSAGE_T *r)
1192{
1193 quagga_get_relative (NULL);
1194#ifdef HAVE_RUSAGE
1195 getrusage(RUSAGE_SELF, &(r->cpu));
1196#endif
1197 r->real = relative_time;
1198
1199#ifdef HAVE_CLOCK_MONOTONIC
1200 /* quagga_get_relative() only updates recent_time if gettimeofday
1201 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1202 * and guarantee to update it before threads are run...
1203 */
1204 quagga_gettimeofday(&recent_time);
1205#endif /* HAVE_CLOCK_MONOTONIC */
1206}
1207
paul718e3742002-12-13 20:15:29 +00001208/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001209 use that to get in-depth stats on the performance of the thread in addition
1210 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001211void
1212thread_call (struct thread *thread)
1213{
ajs8b70d0b2005-04-28 01:31:13 +00001214 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001215 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001216
1217 /* Cache a pointer to the relevant cpu history thread, if the thread
1218 * does not have it yet.
1219 *
1220 * Callers submitting 'dummy threads' hence must take care that
1221 * thread->cpu is NULL
1222 */
1223 if (!thread->hist)
1224 {
1225 struct cpu_thread_history tmp;
1226
1227 tmp.func = thread->func;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +00001228 strcpy(tmp.funcname, thread->funcname);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001229
1230 thread->hist = hash_get (cpu_record, &tmp,
1231 (void * (*) (void *))cpu_record_hash_alloc);
1232 }
paul718e3742002-12-13 20:15:29 +00001233
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001234 GETRUSAGE (&before);
1235 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001236
1237 (*thread->func) (thread);
1238
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001239 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001240
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001241 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001242 thread->hist->real.total += realtime;
1243 if (thread->hist->real.max < realtime)
1244 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001245#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001246 thread->hist->cpu.total += cputime;
1247 if (thread->hist->cpu.max < cputime)
1248 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001249#endif
paule04ab742003-01-17 23:47:00 +00001250
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001251 ++(thread->hist->total_calls);
1252 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001253
ajs924b9222005-04-16 17:11:24 +00001254#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001255 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001256 {
1257 /*
1258 * We have a CPU Hog on our hands.
1259 * Whinge about it now, so we're aware this is yet another task
1260 * to fix.
1261 */
ajs8b70d0b2005-04-28 01:31:13 +00001262 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001263 thread->funcname,
1264 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001265 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001266 }
ajs924b9222005-04-16 17:11:24 +00001267#endif /* CONSUMED_TIME_CHECK */
paul718e3742002-12-13 20:15:29 +00001268}
1269
1270/* Execute thread */
1271struct thread *
paule04ab742003-01-17 23:47:00 +00001272funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001273 int (*func)(struct thread *),
1274 void *arg,
paule04ab742003-01-17 23:47:00 +00001275 int val,
hasso8c328f12004-10-05 21:01:23 +00001276 const char* funcname)
paul718e3742002-12-13 20:15:29 +00001277{
1278 struct thread dummy;
1279
1280 memset (&dummy, 0, sizeof (struct thread));
1281
1282 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001283 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001284 dummy.master = NULL;
1285 dummy.func = func;
1286 dummy.arg = arg;
1287 dummy.u.val = val;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +00001288 strip_funcname (dummy.funcname, funcname);
paul718e3742002-12-13 20:15:29 +00001289 thread_call (&dummy);
1290
paul718e3742002-12-13 20:15:29 +00001291 return NULL;
1292}