blob: 16c92c2467779f68543573d01d6456f3c68c6726 [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
Hasso Tepper3b96b782012-10-11 11:31:54 +000042#if defined(__APPLE__)
43#include <mach/mach.h>
44#include <mach/mach_time.h>
45#endif
46
paule04ab742003-01-17 23:47:00 +000047
Paul Jakmadb9c0df2006-08-27 06:44:02 +000048/* Recent absolute time of day */
ajs8b70d0b2005-04-28 01:31:13 +000049struct timeval recent_time;
Paul Jakmadb9c0df2006-08-27 06:44:02 +000050static struct timeval last_recent_time;
51/* Relative time, since startup */
52static struct timeval relative_time;
53static struct timeval relative_time_base;
54/* init flag */
55static unsigned short timers_inited;
56
paule04ab742003-01-17 23:47:00 +000057static struct hash *cpu_record = NULL;
paul718e3742002-12-13 20:15:29 +000058
59/* Struct timeval's tv_usec one second value. */
60#define TIMER_SECOND_MICRO 1000000L
61
ajs8b70d0b2005-04-28 01:31:13 +000062/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
63 And change negative values to 0. */
paula48b4e62005-04-22 00:43:47 +000064static struct timeval
paul718e3742002-12-13 20:15:29 +000065timeval_adjust (struct timeval a)
66{
67 while (a.tv_usec >= TIMER_SECOND_MICRO)
68 {
69 a.tv_usec -= TIMER_SECOND_MICRO;
70 a.tv_sec++;
71 }
72
73 while (a.tv_usec < 0)
74 {
75 a.tv_usec += TIMER_SECOND_MICRO;
76 a.tv_sec--;
77 }
78
79 if (a.tv_sec < 0)
ajs8b70d0b2005-04-28 01:31:13 +000080 /* Change negative timeouts to 0. */
81 a.tv_sec = a.tv_usec = 0;
paul718e3742002-12-13 20:15:29 +000082
83 return a;
84}
85
86static struct timeval
87timeval_subtract (struct timeval a, struct timeval b)
88{
89 struct timeval ret;
90
91 ret.tv_usec = a.tv_usec - b.tv_usec;
92 ret.tv_sec = a.tv_sec - b.tv_sec;
93
94 return timeval_adjust (ret);
95}
96
ajs8b70d0b2005-04-28 01:31:13 +000097static long
paul718e3742002-12-13 20:15:29 +000098timeval_cmp (struct timeval a, struct timeval b)
99{
100 return (a.tv_sec == b.tv_sec
101 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
102}
103
104static unsigned long
105timeval_elapsed (struct timeval a, struct timeval b)
106{
107 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
108 + (a.tv_usec - b.tv_usec));
109}
110
Hasso Tepper3b96b782012-10-11 11:31:54 +0000111#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000112static void
113quagga_gettimeofday_relative_adjust (void)
114{
115 struct timeval diff;
116 if (timeval_cmp (recent_time, last_recent_time) < 0)
117 {
118 relative_time.tv_sec++;
119 relative_time.tv_usec = 0;
120 }
121 else
122 {
123 diff = timeval_subtract (recent_time, last_recent_time);
124 relative_time.tv_sec += diff.tv_sec;
125 relative_time.tv_usec += diff.tv_usec;
126 relative_time = timeval_adjust (relative_time);
127 }
128 last_recent_time = recent_time;
129}
Hasso Tepper3b96b782012-10-11 11:31:54 +0000130#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000131
132/* gettimeofday wrapper, to keep recent_time updated */
133static int
134quagga_gettimeofday (struct timeval *tv)
135{
136 int ret;
137
138 assert (tv);
139
140 if (!(ret = gettimeofday (&recent_time, NULL)))
141 {
142 /* init... */
143 if (!timers_inited)
144 {
145 relative_time_base = last_recent_time = recent_time;
146 timers_inited = 1;
147 }
148 /* avoid copy if user passed recent_time pointer.. */
149 if (tv != &recent_time)
150 *tv = recent_time;
151 return 0;
152 }
153 return ret;
154}
155
156static int
157quagga_get_relative (struct timeval *tv)
158{
159 int ret;
160
161#ifdef HAVE_CLOCK_MONOTONIC
162 {
163 struct timespec tp;
164 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
165 {
166 relative_time.tv_sec = tp.tv_sec;
167 relative_time.tv_usec = tp.tv_nsec / 1000;
168 }
169 }
Hasso Tepper3b96b782012-10-11 11:31:54 +0000170#elif defined(__APPLE__)
171 {
172 uint64_t ticks;
173 uint64_t useconds;
174 static mach_timebase_info_data_t timebase_info;
175
176 ticks = mach_absolute_time();
177 if (timebase_info.denom == 0)
178 mach_timebase_info(&timebase_info);
179
180 useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
181 relative_time.tv_sec = useconds / 1000000;
182 relative_time.tv_usec = useconds % 1000000;
183
184 return 0;
185 }
186#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000187 if (!(ret = quagga_gettimeofday (&recent_time)))
188 quagga_gettimeofday_relative_adjust();
189#endif /* HAVE_CLOCK_MONOTONIC */
190
191 if (tv)
192 *tv = relative_time;
193
194 return ret;
195}
196
197/* Get absolute time stamp, but in terms of the internal timer
198 * Could be wrong, but at least won't go back.
199 */
200static void
201quagga_real_stabilised (struct timeval *tv)
202{
203 *tv = relative_time_base;
204 tv->tv_sec += relative_time.tv_sec;
205 tv->tv_usec += relative_time.tv_usec;
206 *tv = timeval_adjust (*tv);
207}
208
209/* Exported Quagga timestamp function.
210 * Modelled on POSIX clock_gettime.
211 */
212int
213quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
214{
215 switch (clkid)
216 {
217 case QUAGGA_CLK_REALTIME:
218 return quagga_gettimeofday (tv);
219 case QUAGGA_CLK_MONOTONIC:
220 return quagga_get_relative (tv);
221 case QUAGGA_CLK_REALTIME_STABILISED:
222 quagga_real_stabilised (tv);
223 return 0;
224 default:
225 errno = EINVAL;
226 return -1;
227 }
228}
229
230/* time_t value in terms of stabilised absolute time.
231 * replacement for POSIX time()
232 */
233time_t
234quagga_time (time_t *t)
235{
236 struct timeval tv;
237 quagga_real_stabilised (&tv);
238 if (t)
239 *t = tv.tv_sec;
240 return tv.tv_sec;
241}
242
243/* Public export of recent_relative_time by value */
244struct timeval
245recent_relative_time (void)
246{
247 return relative_time;
248}
249
paula48b4e62005-04-22 00:43:47 +0000250static unsigned int
paule04ab742003-01-17 23:47:00 +0000251cpu_record_hash_key (struct cpu_thread_history *a)
252{
paul8cc41982005-05-06 21:25:49 +0000253 return (uintptr_t) a->func;
paule04ab742003-01-17 23:47:00 +0000254}
255
256static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100257cpu_record_hash_cmp (const struct cpu_thread_history *a,
258 const struct cpu_thread_history *b)
paule04ab742003-01-17 23:47:00 +0000259{
260 return a->func == b->func;
261}
262
paul8cc41982005-05-06 21:25:49 +0000263static void *
paule04ab742003-01-17 23:47:00 +0000264cpu_record_hash_alloc (struct cpu_thread_history *a)
265{
266 struct cpu_thread_history *new;
paul039b9572004-10-31 16:43:17 +0000267 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
paule04ab742003-01-17 23:47:00 +0000268 new->func = a->func;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000269 strcpy(new->funcname, a->funcname);
paule04ab742003-01-17 23:47:00 +0000270 return new;
271}
272
Chris Caputo228da422009-07-18 05:44:03 +0000273static void
274cpu_record_hash_free (void *a)
275{
276 struct cpu_thread_history *hist = a;
277
Chris Caputo228da422009-07-18 05:44:03 +0000278 XFREE (MTYPE_THREAD_STATS, hist);
279}
280
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100281static void
paule04ab742003-01-17 23:47:00 +0000282vty_out_cpu_thread_history(struct vty* vty,
283 struct cpu_thread_history *a)
284{
ajs8b70d0b2005-04-28 01:31:13 +0000285#ifdef HAVE_RUSAGE
286 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
287 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
288 a->cpu.total/a->total_calls, a->cpu.max,
289 a->real.total/a->total_calls, a->real.max);
290#else
291 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
292 a->real.total/1000, a->real.total%1000, a->total_calls,
293 a->real.total/a->total_calls, a->real.max);
294#endif
295 vty_out(vty, " %c%c%c%c%c%c %s%s",
paule04ab742003-01-17 23:47:00 +0000296 a->types & (1 << THREAD_READ) ? 'R':' ',
297 a->types & (1 << THREAD_WRITE) ? 'W':' ',
298 a->types & (1 << THREAD_TIMER) ? 'T':' ',
299 a->types & (1 << THREAD_EVENT) ? 'E':' ',
300 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
paula48b4e62005-04-22 00:43:47 +0000301 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
paule04ab742003-01-17 23:47:00 +0000302 a->funcname, VTY_NEWLINE);
303}
304
305static void
306cpu_record_hash_print(struct hash_backet *bucket,
307 void *args[])
308{
309 struct cpu_thread_history *totals = args[0];
310 struct vty *vty = args[1];
Paul Jakma41b23732009-06-30 16:12:49 +0100311 thread_type *filter = args[2];
paule04ab742003-01-17 23:47:00 +0000312 struct cpu_thread_history *a = bucket->data;
paula48b4e62005-04-22 00:43:47 +0000313
paule04ab742003-01-17 23:47:00 +0000314 a = bucket->data;
315 if ( !(a->types & *filter) )
316 return;
317 vty_out_cpu_thread_history(vty,a);
paule04ab742003-01-17 23:47:00 +0000318 totals->total_calls += a->total_calls;
ajs8b70d0b2005-04-28 01:31:13 +0000319 totals->real.total += a->real.total;
320 if (totals->real.max < a->real.max)
321 totals->real.max = a->real.max;
322#ifdef HAVE_RUSAGE
323 totals->cpu.total += a->cpu.total;
324 if (totals->cpu.max < a->cpu.max)
325 totals->cpu.max = a->cpu.max;
326#endif
paule04ab742003-01-17 23:47:00 +0000327}
328
329static void
Paul Jakma41b23732009-06-30 16:12:49 +0100330cpu_record_print(struct vty *vty, thread_type filter)
paule04ab742003-01-17 23:47:00 +0000331{
332 struct cpu_thread_history tmp;
333 void *args[3] = {&tmp, vty, &filter};
334
335 memset(&tmp, 0, sizeof tmp);
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000336 strcpy(tmp.funcname, "TOTAL");
paule04ab742003-01-17 23:47:00 +0000337 tmp.types = filter;
338
ajs8b70d0b2005-04-28 01:31:13 +0000339#ifdef HAVE_RUSAGE
340 vty_out(vty, "%21s %18s %18s%s",
341 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
342#endif
343 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
344#ifdef HAVE_RUSAGE
345 vty_out(vty, " Avg uSec Max uSecs");
346#endif
347 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
paule04ab742003-01-17 23:47:00 +0000348 hash_iterate(cpu_record,
349 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
350 args);
351
352 if (tmp.total_calls > 0)
353 vty_out_cpu_thread_history(vty, &tmp);
354}
355
356DEFUN(show_thread_cpu,
357 show_thread_cpu_cmd,
358 "show thread cpu [FILTER]",
359 SHOW_STR
360 "Thread information\n"
361 "Thread CPU usage\n"
paula48b4e62005-04-22 00:43:47 +0000362 "Display filter (rwtexb)\n")
paule04ab742003-01-17 23:47:00 +0000363{
364 int i = 0;
Paul Jakma41b23732009-06-30 16:12:49 +0100365 thread_type filter = (thread_type) -1U;
paule04ab742003-01-17 23:47:00 +0000366
367 if (argc > 0)
368 {
369 filter = 0;
370 while (argv[0][i] != '\0')
371 {
372 switch ( argv[0][i] )
373 {
374 case 'r':
375 case 'R':
376 filter |= (1 << THREAD_READ);
377 break;
378 case 'w':
379 case 'W':
380 filter |= (1 << THREAD_WRITE);
381 break;
382 case 't':
383 case 'T':
384 filter |= (1 << THREAD_TIMER);
385 break;
386 case 'e':
387 case 'E':
388 filter |= (1 << THREAD_EVENT);
389 break;
390 case 'x':
391 case 'X':
392 filter |= (1 << THREAD_EXECUTE);
393 break;
paula48b4e62005-04-22 00:43:47 +0000394 case 'b':
395 case 'B':
396 filter |= (1 << THREAD_BACKGROUND);
397 break;
paule04ab742003-01-17 23:47:00 +0000398 default:
399 break;
400 }
401 ++i;
402 }
403 if (filter == 0)
404 {
paula48b4e62005-04-22 00:43:47 +0000405 vty_out(vty, "Invalid filter \"%s\" specified,"
406 " must contain at least one of 'RWTEXB'%s",
paule04ab742003-01-17 23:47:00 +0000407 argv[0], VTY_NEWLINE);
408 return CMD_WARNING;
409 }
410 }
411
412 cpu_record_print(vty, filter);
413 return CMD_SUCCESS;
414}
Paul Jakmae276eb82010-01-09 16:15:00 +0000415
416static void
417cpu_record_hash_clear (struct hash_backet *bucket,
418 void *args)
419{
420 thread_type *filter = args;
421 struct cpu_thread_history *a = bucket->data;
422
423 a = bucket->data;
424 if ( !(a->types & *filter) )
425 return;
426
427 hash_release (cpu_record, bucket->data);
428}
429
430static void
431cpu_record_clear (thread_type filter)
432{
433 thread_type *tmp = &filter;
434 hash_iterate (cpu_record,
435 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
436 tmp);
437}
438
439DEFUN(clear_thread_cpu,
440 clear_thread_cpu_cmd,
441 "clear thread cpu [FILTER]",
442 "Clear stored data\n"
443 "Thread information\n"
444 "Thread CPU usage\n"
445 "Display filter (rwtexb)\n")
446{
447 int i = 0;
448 thread_type filter = (thread_type) -1U;
449
450 if (argc > 0)
451 {
452 filter = 0;
453 while (argv[0][i] != '\0')
454 {
455 switch ( argv[0][i] )
456 {
457 case 'r':
458 case 'R':
459 filter |= (1 << THREAD_READ);
460 break;
461 case 'w':
462 case 'W':
463 filter |= (1 << THREAD_WRITE);
464 break;
465 case 't':
466 case 'T':
467 filter |= (1 << THREAD_TIMER);
468 break;
469 case 'e':
470 case 'E':
471 filter |= (1 << THREAD_EVENT);
472 break;
473 case 'x':
474 case 'X':
475 filter |= (1 << THREAD_EXECUTE);
476 break;
477 case 'b':
478 case 'B':
479 filter |= (1 << THREAD_BACKGROUND);
480 break;
481 default:
482 break;
483 }
484 ++i;
485 }
486 if (filter == 0)
487 {
488 vty_out(vty, "Invalid filter \"%s\" specified,"
489 " must contain at least one of 'RWTEXB'%s",
490 argv[0], VTY_NEWLINE);
491 return CMD_WARNING;
492 }
493 }
494
495 cpu_record_clear (filter);
496 return CMD_SUCCESS;
497}
paule04ab742003-01-17 23:47:00 +0000498
paul718e3742002-12-13 20:15:29 +0000499/* List allocation and head/tail print out. */
500static void
501thread_list_debug (struct thread_list *list)
502{
503 printf ("count [%d] head [%p] tail [%p]\n",
504 list->count, list->head, list->tail);
505}
506
507/* Debug print for thread_master. */
paul8cc41982005-05-06 21:25:49 +0000508static void __attribute__ ((unused))
paul718e3742002-12-13 20:15:29 +0000509thread_master_debug (struct thread_master *m)
510{
511 printf ("-----------\n");
512 printf ("readlist : ");
513 thread_list_debug (&m->read);
514 printf ("writelist : ");
515 thread_list_debug (&m->write);
516 printf ("timerlist : ");
517 thread_list_debug (&m->timer);
518 printf ("eventlist : ");
519 thread_list_debug (&m->event);
520 printf ("unuselist : ");
521 thread_list_debug (&m->unuse);
paula48b4e62005-04-22 00:43:47 +0000522 printf ("bgndlist : ");
523 thread_list_debug (&m->background);
paul718e3742002-12-13 20:15:29 +0000524 printf ("total alloc: [%ld]\n", m->alloc);
525 printf ("-----------\n");
526}
527
528/* Allocate new thread master. */
529struct thread_master *
530thread_master_create ()
531{
paule04ab742003-01-17 23:47:00 +0000532 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000533 cpu_record
534 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100535 (int (*) (const void *, const void *))cpu_record_hash_cmp);
paula48b4e62005-04-22 00:43:47 +0000536
paul718e3742002-12-13 20:15:29 +0000537 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
538 sizeof (struct thread_master));
539}
540
541/* Add a new thread to the list. */
542static void
543thread_list_add (struct thread_list *list, struct thread *thread)
544{
545 thread->next = NULL;
546 thread->prev = list->tail;
547 if (list->tail)
548 list->tail->next = thread;
549 else
550 list->head = thread;
551 list->tail = thread;
552 list->count++;
553}
554
555/* Add a new thread just before the point. */
556static void
557thread_list_add_before (struct thread_list *list,
558 struct thread *point,
559 struct thread *thread)
560{
561 thread->next = point;
562 thread->prev = point->prev;
563 if (point->prev)
564 point->prev->next = thread;
565 else
566 list->head = thread;
567 point->prev = thread;
568 list->count++;
569}
570
571/* Delete a thread from the list. */
572static struct thread *
573thread_list_delete (struct thread_list *list, struct thread *thread)
574{
575 if (thread->next)
576 thread->next->prev = thread->prev;
577 else
578 list->tail = thread->prev;
579 if (thread->prev)
580 thread->prev->next = thread->next;
581 else
582 list->head = thread->next;
583 thread->next = thread->prev = NULL;
584 list->count--;
585 return thread;
586}
587
588/* Move thread to unuse list. */
589static void
590thread_add_unuse (struct thread_master *m, struct thread *thread)
591{
paula48b4e62005-04-22 00:43:47 +0000592 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000593 assert (thread->next == NULL);
594 assert (thread->prev == NULL);
595 assert (thread->type == THREAD_UNUSED);
596 thread_list_add (&m->unuse, thread);
paul9d11a192004-10-31 16:19:24 +0000597 /* XXX: Should we deallocate funcname here? */
paul718e3742002-12-13 20:15:29 +0000598}
599
600/* Free all unused thread. */
601static void
602thread_list_free (struct thread_master *m, struct thread_list *list)
603{
604 struct thread *t;
605 struct thread *next;
606
607 for (t = list->head; t; t = next)
608 {
609 next = t->next;
610 XFREE (MTYPE_THREAD, t);
611 list->count--;
612 m->alloc--;
613 }
614}
615
616/* Stop thread scheduler. */
617void
618thread_master_free (struct thread_master *m)
619{
620 thread_list_free (m, &m->read);
621 thread_list_free (m, &m->write);
622 thread_list_free (m, &m->timer);
623 thread_list_free (m, &m->event);
624 thread_list_free (m, &m->ready);
625 thread_list_free (m, &m->unuse);
paula48b4e62005-04-22 00:43:47 +0000626 thread_list_free (m, &m->background);
627
paul718e3742002-12-13 20:15:29 +0000628 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000629
630 if (cpu_record)
631 {
632 hash_clean (cpu_record, cpu_record_hash_free);
633 hash_free (cpu_record);
634 cpu_record = NULL;
635 }
paul718e3742002-12-13 20:15:29 +0000636}
637
paul8cc41982005-05-06 21:25:49 +0000638/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100639static int
paul8cc41982005-05-06 21:25:49 +0000640thread_empty (struct thread_list *list)
641{
642 return list->head ? 0 : 1;
643}
644
paul718e3742002-12-13 20:15:29 +0000645/* Delete top of the list and return it. */
646static struct thread *
647thread_trim_head (struct thread_list *list)
648{
paul8cc41982005-05-06 21:25:49 +0000649 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000650 return thread_list_delete (list, list->head);
651 return NULL;
652}
653
paul718e3742002-12-13 20:15:29 +0000654/* Return remain time in second. */
655unsigned long
656thread_timer_remain_second (struct thread *thread)
657{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000658 quagga_get_relative (NULL);
659
660 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
661 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000662 else
663 return 0;
664}
665
paule04ab742003-01-17 23:47:00 +0000666/* Trim blankspace and "()"s */
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000667void
668strip_funcname (char *dest, const char *funcname)
paule04ab742003-01-17 23:47:00 +0000669{
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000670 char buff[FUNCNAME_LEN];
671 char tmp, *e, *b = buff;
paule04ab742003-01-17 23:47:00 +0000672
673 strncpy(buff, funcname, sizeof(buff));
674 buff[ sizeof(buff) -1] = '\0';
675 e = buff +strlen(buff) -1;
676
677 /* Wont work for funcname == "Word (explanation)" */
678
679 while (*b == ' ' || *b == '(')
680 ++b;
681 while (*e == ' ' || *e == ')')
682 --e;
683 e++;
684
685 tmp = *e;
686 *e = '\0';
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000687 strcpy (dest, b);
paule04ab742003-01-17 23:47:00 +0000688 *e = tmp;
paule04ab742003-01-17 23:47:00 +0000689}
690
paul718e3742002-12-13 20:15:29 +0000691/* Get new thread. */
692static struct thread *
693thread_get (struct thread_master *m, u_char type,
hasso8c328f12004-10-05 21:01:23 +0000694 int (*func) (struct thread *), void *arg, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000695{
Jorge Boncompte [DTI2]64018322012-05-07 16:53:13 +0000696 struct thread *thread = thread_trim_head (&m->unuse);
paul718e3742002-12-13 20:15:29 +0000697
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000698 if (! thread)
paul718e3742002-12-13 20:15:29 +0000699 {
700 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
701 m->alloc++;
702 }
703 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000704 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000705 thread->master = m;
706 thread->func = func;
707 thread->arg = arg;
708
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000709 strip_funcname (thread->funcname, funcname);
paule04ab742003-01-17 23:47:00 +0000710
paul718e3742002-12-13 20:15:29 +0000711 return thread;
712}
713
714/* Add new read thread. */
715struct thread *
paule04ab742003-01-17 23:47:00 +0000716funcname_thread_add_read (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000717 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000718{
719 struct thread *thread;
720
721 assert (m != NULL);
722
723 if (FD_ISSET (fd, &m->readfd))
724 {
725 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
726 return NULL;
727 }
728
paule04ab742003-01-17 23:47:00 +0000729 thread = thread_get (m, THREAD_READ, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000730 FD_SET (fd, &m->readfd);
731 thread->u.fd = fd;
732 thread_list_add (&m->read, thread);
733
734 return thread;
735}
736
737/* Add new write thread. */
738struct thread *
paule04ab742003-01-17 23:47:00 +0000739funcname_thread_add_write (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000740 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000741{
742 struct thread *thread;
743
744 assert (m != NULL);
745
746 if (FD_ISSET (fd, &m->writefd))
747 {
748 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
749 return NULL;
750 }
751
paule04ab742003-01-17 23:47:00 +0000752 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000753 FD_SET (fd, &m->writefd);
754 thread->u.fd = fd;
755 thread_list_add (&m->write, thread);
756
757 return thread;
758}
759
paul98c91ac2004-10-05 14:57:50 +0000760static struct thread *
761funcname_thread_add_timer_timeval (struct thread_master *m,
762 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000763 int type,
paul98c91ac2004-10-05 14:57:50 +0000764 void *arg,
765 struct timeval *time_relative,
hasso8c328f12004-10-05 21:01:23 +0000766 const char* funcname)
paul718e3742002-12-13 20:15:29 +0000767{
paul718e3742002-12-13 20:15:29 +0000768 struct thread *thread;
paula48b4e62005-04-22 00:43:47 +0000769 struct thread_list *list;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000770 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000771 struct thread *tt;
paul718e3742002-12-13 20:15:29 +0000772
773 assert (m != NULL);
774
ajs8b70d0b2005-04-28 01:31:13 +0000775 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000776 assert (time_relative);
777
ajs8b70d0b2005-04-28 01:31:13 +0000778 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
paula48b4e62005-04-22 00:43:47 +0000779 thread = thread_get (m, type, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000780
781 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100782 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000783 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
784 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000785 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000786
787 /* Sort by timeval. */
paula48b4e62005-04-22 00:43:47 +0000788 for (tt = list->head; tt; tt = tt->next)
paul718e3742002-12-13 20:15:29 +0000789 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
790 break;
791
792 if (tt)
paula48b4e62005-04-22 00:43:47 +0000793 thread_list_add_before (list, tt, thread);
paul718e3742002-12-13 20:15:29 +0000794 else
paula48b4e62005-04-22 00:43:47 +0000795 thread_list_add (list, thread);
paul718e3742002-12-13 20:15:29 +0000796
797 return thread;
798}
799
paul98c91ac2004-10-05 14:57:50 +0000800
801/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000802struct thread *
paul98c91ac2004-10-05 14:57:50 +0000803funcname_thread_add_timer (struct thread_master *m,
804 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000805 void *arg, long timer, const char* funcname)
jardin9e867fe2003-12-23 08:56:18 +0000806{
paul98c91ac2004-10-05 14:57:50 +0000807 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000808
809 assert (m != NULL);
810
paul9076fbd2004-10-11 09:40:58 +0000811 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000812 trel.tv_usec = 0;
813
paula48b4e62005-04-22 00:43:47 +0000814 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
815 &trel, funcname);
paul98c91ac2004-10-05 14:57:50 +0000816}
817
818/* Add timer event thread with "millisecond" resolution */
819struct thread *
820funcname_thread_add_timer_msec (struct thread_master *m,
821 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000822 void *arg, long timer, const char* funcname)
paul98c91ac2004-10-05 14:57:50 +0000823{
824 struct timeval trel;
825
826 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000827
ajsaf04bd72004-12-28 17:00:12 +0000828 trel.tv_sec = timer / 1000;
829 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000830
paula48b4e62005-04-22 00:43:47 +0000831 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
832 arg, &trel, funcname);
833}
834
835/* Add a background thread, with an optional millisec delay */
836struct thread *
837funcname_thread_add_background (struct thread_master *m,
838 int (*func) (struct thread *),
839 void *arg, long delay,
840 const char *funcname)
841{
842 struct timeval trel;
843
844 assert (m != NULL);
845
846 if (delay)
847 {
848 trel.tv_sec = delay / 1000;
849 trel.tv_usec = 1000*(delay % 1000);
850 }
851 else
852 {
853 trel.tv_sec = 0;
854 trel.tv_usec = 0;
855 }
856
857 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
858 arg, &trel, funcname);
jardin9e867fe2003-12-23 08:56:18 +0000859}
860
paul718e3742002-12-13 20:15:29 +0000861/* Add simple event thread. */
862struct thread *
paule04ab742003-01-17 23:47:00 +0000863funcname_thread_add_event (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000864 int (*func) (struct thread *), void *arg, int val, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000865{
866 struct thread *thread;
867
868 assert (m != NULL);
869
paule04ab742003-01-17 23:47:00 +0000870 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000871 thread->u.val = val;
872 thread_list_add (&m->event, thread);
873
874 return thread;
875}
876
877/* Cancel thread from scheduler. */
878void
879thread_cancel (struct thread *thread)
880{
paula48b4e62005-04-22 00:43:47 +0000881 struct thread_list *list;
882
paul718e3742002-12-13 20:15:29 +0000883 switch (thread->type)
884 {
885 case THREAD_READ:
886 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
887 FD_CLR (thread->u.fd, &thread->master->readfd);
paula48b4e62005-04-22 00:43:47 +0000888 list = &thread->master->read;
paul718e3742002-12-13 20:15:29 +0000889 break;
890 case THREAD_WRITE:
891 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
892 FD_CLR (thread->u.fd, &thread->master->writefd);
paula48b4e62005-04-22 00:43:47 +0000893 list = &thread->master->write;
paul718e3742002-12-13 20:15:29 +0000894 break;
895 case THREAD_TIMER:
paula48b4e62005-04-22 00:43:47 +0000896 list = &thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000897 break;
898 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000899 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000900 break;
901 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000902 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000903 break;
paula48b4e62005-04-22 00:43:47 +0000904 case THREAD_BACKGROUND:
905 list = &thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000906 break;
paul718e3742002-12-13 20:15:29 +0000907 default:
paula48b4e62005-04-22 00:43:47 +0000908 return;
paul718e3742002-12-13 20:15:29 +0000909 break;
910 }
paula48b4e62005-04-22 00:43:47 +0000911 thread_list_delete (list, thread);
paul718e3742002-12-13 20:15:29 +0000912 thread->type = THREAD_UNUSED;
913 thread_add_unuse (thread->master, thread);
914}
915
916/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +0000917unsigned int
paul718e3742002-12-13 20:15:29 +0000918thread_cancel_event (struct thread_master *m, void *arg)
919{
pauldc818072005-05-19 01:30:53 +0000920 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +0000921 struct thread *thread;
922
923 thread = m->event.head;
924 while (thread)
925 {
926 struct thread *t;
927
928 t = thread;
929 thread = t->next;
930
931 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +0000932 {
pauldc818072005-05-19 01:30:53 +0000933 ret++;
paula48b4e62005-04-22 00:43:47 +0000934 thread_list_delete (&m->event, t);
935 t->type = THREAD_UNUSED;
936 thread_add_unuse (m, t);
937 }
paul718e3742002-12-13 20:15:29 +0000938 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +0000939
940 /* thread can be on the ready list too */
941 thread = m->ready.head;
942 while (thread)
943 {
944 struct thread *t;
945
946 t = thread;
947 thread = t->next;
948
949 if (t->arg == arg)
950 {
951 ret++;
952 thread_list_delete (&m->ready, t);
953 t->type = THREAD_UNUSED;
954 thread_add_unuse (m, t);
955 }
956 }
pauldc818072005-05-19 01:30:53 +0000957 return ret;
paul718e3742002-12-13 20:15:29 +0000958}
959
paula48b4e62005-04-22 00:43:47 +0000960static struct timeval *
961thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +0000962{
paul8cc41982005-05-06 21:25:49 +0000963 if (!thread_empty (tlist))
paul718e3742002-12-13 20:15:29 +0000964 {
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000965 *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +0000966 return timer_val;
967 }
968 return NULL;
969}
paul718e3742002-12-13 20:15:29 +0000970
paul8cc41982005-05-06 21:25:49 +0000971static struct thread *
paul718e3742002-12-13 20:15:29 +0000972thread_run (struct thread_master *m, struct thread *thread,
973 struct thread *fetch)
974{
975 *fetch = *thread;
976 thread->type = THREAD_UNUSED;
977 thread_add_unuse (m, thread);
978 return fetch;
979}
980
paula48b4e62005-04-22 00:43:47 +0000981static int
982thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
paul718e3742002-12-13 20:15:29 +0000983{
984 struct thread *thread;
985 struct thread *next;
986 int ready = 0;
paula48b4e62005-04-22 00:43:47 +0000987
988 assert (list);
989
paul718e3742002-12-13 20:15:29 +0000990 for (thread = list->head; thread; thread = next)
991 {
992 next = thread->next;
993
994 if (FD_ISSET (THREAD_FD (thread), fdset))
paula48b4e62005-04-22 00:43:47 +0000995 {
996 assert (FD_ISSET (THREAD_FD (thread), mfdset));
997 FD_CLR(THREAD_FD (thread), mfdset);
998 thread_list_delete (list, thread);
999 thread_list_add (&thread->master->ready, thread);
1000 thread->type = THREAD_READY;
1001 ready++;
1002 }
paul718e3742002-12-13 20:15:29 +00001003 }
1004 return ready;
1005}
1006
ajs8b70d0b2005-04-28 01:31:13 +00001007/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +00001008static unsigned int
1009thread_timer_process (struct thread_list *list, struct timeval *timenow)
1010{
1011 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001012 struct thread *next;
paula48b4e62005-04-22 00:43:47 +00001013 unsigned int ready = 0;
1014
Paul Jakmab5043aa2012-02-28 18:32:56 +00001015 for (thread = list->head; thread; thread = next)
ajs8b70d0b2005-04-28 01:31:13 +00001016 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001017 next = thread->next;
ajs8b70d0b2005-04-28 01:31:13 +00001018 if (timeval_cmp (*timenow, thread->u.sands) < 0)
1019 return ready;
1020 thread_list_delete (list, thread);
1021 thread->type = THREAD_READY;
1022 thread_list_add (&thread->master->ready, thread);
1023 ready++;
1024 }
paula48b4e62005-04-22 00:43:47 +00001025 return ready;
1026}
1027
Paul Jakma2613abe2010-01-11 16:33:07 +00001028/* process a list en masse, e.g. for event thread lists */
1029static unsigned int
1030thread_process (struct thread_list *list)
1031{
1032 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001033 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001034 unsigned int ready = 0;
1035
Paul Jakmab5043aa2012-02-28 18:32:56 +00001036 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001037 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001038 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001039 thread_list_delete (list, thread);
1040 thread->type = THREAD_READY;
1041 thread_list_add (&thread->master->ready, thread);
1042 ready++;
1043 }
1044 return ready;
1045}
1046
1047
paul718e3742002-12-13 20:15:29 +00001048/* Fetch next ready thread. */
1049struct thread *
1050thread_fetch (struct thread_master *m, struct thread *fetch)
1051{
paul718e3742002-12-13 20:15:29 +00001052 struct thread *thread;
1053 fd_set readfd;
1054 fd_set writefd;
1055 fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001056 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001057 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001058 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001059 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001060
1061 while (1)
1062 {
paula48b4e62005-04-22 00:43:47 +00001063 int num = 0;
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001064#if defined HAVE_SNMP && defined SNMP_AGENTX
1065 struct timeval snmp_timer_wait;
1066 int snmpblock = 0;
1067 int fdsetsize;
1068#endif
paula48b4e62005-04-22 00:43:47 +00001069
Paul Jakma2613abe2010-01-11 16:33:07 +00001070 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001071 quagga_sigevent_process ();
1072
Paul Jakma2613abe2010-01-11 16:33:07 +00001073 /* Drain the ready queue of already scheduled jobs, before scheduling
1074 * more.
paula48b4e62005-04-22 00:43:47 +00001075 */
paul718e3742002-12-13 20:15:29 +00001076 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001077 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001078
Paul Jakma2613abe2010-01-11 16:33:07 +00001079 /* To be fair to all kinds of threads, and avoid starvation, we
1080 * need to be careful to consider all thread types for scheduling
1081 * in each quanta. I.e. we should not return early from here on.
1082 */
1083
1084 /* Normal event are the next highest priority. */
1085 thread_process (&m->event);
1086
paul718e3742002-12-13 20:15:29 +00001087 /* Structure copy. */
1088 readfd = m->readfd;
1089 writefd = m->writefd;
1090 exceptfd = m->exceptfd;
paula48b4e62005-04-22 00:43:47 +00001091
1092 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001093 if (m->ready.count == 0)
1094 {
1095 quagga_get_relative (NULL);
1096 timer_wait = thread_timer_wait (&m->timer, &timer_val);
1097 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
1098
1099 if (timer_wait_bg &&
1100 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1101 timer_wait = timer_wait_bg;
1102 }
paula48b4e62005-04-22 00:43:47 +00001103
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001104#if defined HAVE_SNMP && defined SNMP_AGENTX
1105 /* When SNMP is enabled, we may have to select() on additional
1106 FD. snmp_select_info() will add them to `readfd'. The trick
1107 with this function is its last argument. We need to set it to
1108 0 if timer_wait is not NULL and we need to use the provided
1109 new timer only if it is still set to 0. */
1110 if (agentx_enabled)
1111 {
1112 fdsetsize = FD_SETSIZE;
1113 snmpblock = 1;
1114 if (timer_wait)
1115 {
1116 snmpblock = 0;
1117 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
1118 }
1119 snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
1120 if (snmpblock == 0)
1121 timer_wait = &snmp_timer_wait;
1122 }
1123#endif
paul718e3742002-12-13 20:15:29 +00001124 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001125
1126 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001127 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001128 {
1129 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001130 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001131 zlog_warn ("select() error: %s", safe_strerror (errno));
paul05c447d2004-07-22 19:14:27 +00001132 return NULL;
1133 }
ajs8b70d0b2005-04-28 01:31:13 +00001134
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001135#if defined HAVE_SNMP && defined SNMP_AGENTX
1136 if (agentx_enabled)
1137 {
1138 if (num > 0)
1139 snmp_read(&readfd);
1140 else if (num == 0)
1141 {
1142 snmp_timeout();
1143 run_alarms();
1144 }
1145 netsnmp_check_outstanding_agent_requests();
1146 }
1147#endif
1148
ajs8b70d0b2005-04-28 01:31:13 +00001149 /* Check foreground timers. Historically, they have had higher
1150 priority than I/O threads, so let's push them onto the ready
1151 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001152 quagga_get_relative (NULL);
1153 thread_timer_process (&m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001154
1155 /* Got IO, process it */
1156 if (num > 0)
1157 {
1158 /* Normal priority read thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001159 thread_process_fd (&m->read, &readfd, &m->readfd);
paula48b4e62005-04-22 00:43:47 +00001160 /* Write thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001161 thread_process_fd (&m->write, &writefd, &m->writefd);
paula48b4e62005-04-22 00:43:47 +00001162 }
ajs8b70d0b2005-04-28 01:31:13 +00001163
1164#if 0
1165 /* If any threads were made ready above (I/O or foreground timer),
1166 perhaps we should avoid adding background timers to the ready
1167 list at this time. If this is code is uncommented, then background
1168 timer threads will not run unless there is nothing else to do. */
1169 if ((thread = thread_trim_head (&m->ready)) != NULL)
1170 return thread_run (m, thread, fetch);
1171#endif
1172
paula48b4e62005-04-22 00:43:47 +00001173 /* Background timer/events, lowest priority */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001174 thread_timer_process (&m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001175
ajs8b70d0b2005-04-28 01:31:13 +00001176 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001177 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001178 }
1179}
1180
ajs924b9222005-04-16 17:11:24 +00001181unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001182thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001183{
paul718e3742002-12-13 20:15:29 +00001184#ifdef HAVE_RUSAGE
1185 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001186 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1187 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001188#else
ajs8b70d0b2005-04-28 01:31:13 +00001189 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001190#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001191 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001192}
1193
ajs8b70d0b2005-04-28 01:31:13 +00001194/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1195 Note: we are using real (wall clock) time for this calculation.
1196 It could be argued that CPU time may make more sense in certain
1197 contexts. The things to consider are whether the thread may have
1198 blocked (in which case wall time increases, but CPU time does not),
1199 or whether the system is heavily loaded with other processes competing
1200 for CPU time. On balance, wall clock time seems to make sense.
1201 Plus it has the added benefit that gettimeofday should be faster
1202 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001203int
1204thread_should_yield (struct thread *thread)
1205{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001206 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001207 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001208 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001209}
1210
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001211void
1212thread_getrusage (RUSAGE_T *r)
1213{
1214 quagga_get_relative (NULL);
1215#ifdef HAVE_RUSAGE
1216 getrusage(RUSAGE_SELF, &(r->cpu));
1217#endif
1218 r->real = relative_time;
1219
1220#ifdef HAVE_CLOCK_MONOTONIC
1221 /* quagga_get_relative() only updates recent_time if gettimeofday
1222 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1223 * and guarantee to update it before threads are run...
1224 */
1225 quagga_gettimeofday(&recent_time);
1226#endif /* HAVE_CLOCK_MONOTONIC */
1227}
1228
paul718e3742002-12-13 20:15:29 +00001229/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001230 use that to get in-depth stats on the performance of the thread in addition
1231 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001232void
1233thread_call (struct thread *thread)
1234{
ajs8b70d0b2005-04-28 01:31:13 +00001235 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001236 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001237
1238 /* Cache a pointer to the relevant cpu history thread, if the thread
1239 * does not have it yet.
1240 *
1241 * Callers submitting 'dummy threads' hence must take care that
1242 * thread->cpu is NULL
1243 */
1244 if (!thread->hist)
1245 {
1246 struct cpu_thread_history tmp;
1247
1248 tmp.func = thread->func;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +00001249 strcpy(tmp.funcname, thread->funcname);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001250
1251 thread->hist = hash_get (cpu_record, &tmp,
1252 (void * (*) (void *))cpu_record_hash_alloc);
1253 }
paul718e3742002-12-13 20:15:29 +00001254
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001255 GETRUSAGE (&before);
1256 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001257
1258 (*thread->func) (thread);
1259
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001260 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001261
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001262 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001263 thread->hist->real.total += realtime;
1264 if (thread->hist->real.max < realtime)
1265 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001266#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001267 thread->hist->cpu.total += cputime;
1268 if (thread->hist->cpu.max < cputime)
1269 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001270#endif
paule04ab742003-01-17 23:47:00 +00001271
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001272 ++(thread->hist->total_calls);
1273 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001274
ajs924b9222005-04-16 17:11:24 +00001275#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001276 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001277 {
1278 /*
1279 * We have a CPU Hog on our hands.
1280 * Whinge about it now, so we're aware this is yet another task
1281 * to fix.
1282 */
ajs8b70d0b2005-04-28 01:31:13 +00001283 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001284 thread->funcname,
1285 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001286 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001287 }
ajs924b9222005-04-16 17:11:24 +00001288#endif /* CONSUMED_TIME_CHECK */
paul718e3742002-12-13 20:15:29 +00001289}
1290
1291/* Execute thread */
1292struct thread *
paule04ab742003-01-17 23:47:00 +00001293funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001294 int (*func)(struct thread *),
1295 void *arg,
paule04ab742003-01-17 23:47:00 +00001296 int val,
hasso8c328f12004-10-05 21:01:23 +00001297 const char* funcname)
paul718e3742002-12-13 20:15:29 +00001298{
1299 struct thread dummy;
1300
1301 memset (&dummy, 0, sizeof (struct thread));
1302
1303 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001304 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001305 dummy.master = NULL;
1306 dummy.func = func;
1307 dummy.arg = arg;
1308 dummy.u.val = val;
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +00001309 strip_funcname (dummy.funcname, funcname);
paul718e3742002-12-13 20:15:29 +00001310 thread_call (&dummy);
1311
paul718e3742002-12-13 20:15:29 +00001312 return NULL;
1313}