blob: 784b29c67c1b5f49f87ebbd96015c9a68d4afce2 [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"
paule04ab742003-01-17 23:47:00 +000032
Paul Jakmadb9c0df2006-08-27 06:44:02 +000033/* Recent absolute time of day */
ajs8b70d0b2005-04-28 01:31:13 +000034struct timeval recent_time;
Paul Jakmadb9c0df2006-08-27 06:44:02 +000035static struct timeval last_recent_time;
36/* Relative time, since startup */
37static struct timeval relative_time;
38static struct timeval relative_time_base;
39/* init flag */
40static unsigned short timers_inited;
41
paule04ab742003-01-17 23:47:00 +000042static struct hash *cpu_record = NULL;
paul718e3742002-12-13 20:15:29 +000043
44/* Struct timeval's tv_usec one second value. */
45#define TIMER_SECOND_MICRO 1000000L
46
ajs8b70d0b2005-04-28 01:31:13 +000047/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
48 And change negative values to 0. */
paula48b4e62005-04-22 00:43:47 +000049static struct timeval
paul718e3742002-12-13 20:15:29 +000050timeval_adjust (struct timeval a)
51{
52 while (a.tv_usec >= TIMER_SECOND_MICRO)
53 {
54 a.tv_usec -= TIMER_SECOND_MICRO;
55 a.tv_sec++;
56 }
57
58 while (a.tv_usec < 0)
59 {
60 a.tv_usec += TIMER_SECOND_MICRO;
61 a.tv_sec--;
62 }
63
64 if (a.tv_sec < 0)
ajs8b70d0b2005-04-28 01:31:13 +000065 /* Change negative timeouts to 0. */
66 a.tv_sec = a.tv_usec = 0;
paul718e3742002-12-13 20:15:29 +000067
68 return a;
69}
70
71static struct timeval
72timeval_subtract (struct timeval a, struct timeval b)
73{
74 struct timeval ret;
75
76 ret.tv_usec = a.tv_usec - b.tv_usec;
77 ret.tv_sec = a.tv_sec - b.tv_sec;
78
79 return timeval_adjust (ret);
80}
81
ajs8b70d0b2005-04-28 01:31:13 +000082static long
paul718e3742002-12-13 20:15:29 +000083timeval_cmp (struct timeval a, struct timeval b)
84{
85 return (a.tv_sec == b.tv_sec
86 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
87}
88
89static unsigned long
90timeval_elapsed (struct timeval a, struct timeval b)
91{
92 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
93 + (a.tv_usec - b.tv_usec));
94}
95
Paul Jakmadb9c0df2006-08-27 06:44:02 +000096#ifndef HAVE_CLOCK_MONOTONIC
97static void
98quagga_gettimeofday_relative_adjust (void)
99{
100 struct timeval diff;
101 if (timeval_cmp (recent_time, last_recent_time) < 0)
102 {
103 relative_time.tv_sec++;
104 relative_time.tv_usec = 0;
105 }
106 else
107 {
108 diff = timeval_subtract (recent_time, last_recent_time);
109 relative_time.tv_sec += diff.tv_sec;
110 relative_time.tv_usec += diff.tv_usec;
111 relative_time = timeval_adjust (relative_time);
112 }
113 last_recent_time = recent_time;
114}
115#endif /* !HAVE_CLOCK_MONOTONIC */
116
117/* gettimeofday wrapper, to keep recent_time updated */
118static int
119quagga_gettimeofday (struct timeval *tv)
120{
121 int ret;
122
123 assert (tv);
124
125 if (!(ret = gettimeofday (&recent_time, NULL)))
126 {
127 /* init... */
128 if (!timers_inited)
129 {
130 relative_time_base = last_recent_time = recent_time;
131 timers_inited = 1;
132 }
133 /* avoid copy if user passed recent_time pointer.. */
134 if (tv != &recent_time)
135 *tv = recent_time;
136 return 0;
137 }
138 return ret;
139}
140
141static int
142quagga_get_relative (struct timeval *tv)
143{
144 int ret;
145
146#ifdef HAVE_CLOCK_MONOTONIC
147 {
148 struct timespec tp;
149 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
150 {
151 relative_time.tv_sec = tp.tv_sec;
152 relative_time.tv_usec = tp.tv_nsec / 1000;
153 }
154 }
155#else /* !HAVE_CLOCK_MONOTONIC */
156 if (!(ret = quagga_gettimeofday (&recent_time)))
157 quagga_gettimeofday_relative_adjust();
158#endif /* HAVE_CLOCK_MONOTONIC */
159
160 if (tv)
161 *tv = relative_time;
162
163 return ret;
164}
165
166/* Get absolute time stamp, but in terms of the internal timer
167 * Could be wrong, but at least won't go back.
168 */
169static void
170quagga_real_stabilised (struct timeval *tv)
171{
172 *tv = relative_time_base;
173 tv->tv_sec += relative_time.tv_sec;
174 tv->tv_usec += relative_time.tv_usec;
175 *tv = timeval_adjust (*tv);
176}
177
178/* Exported Quagga timestamp function.
179 * Modelled on POSIX clock_gettime.
180 */
181int
182quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
183{
184 switch (clkid)
185 {
186 case QUAGGA_CLK_REALTIME:
187 return quagga_gettimeofday (tv);
188 case QUAGGA_CLK_MONOTONIC:
189 return quagga_get_relative (tv);
190 case QUAGGA_CLK_REALTIME_STABILISED:
191 quagga_real_stabilised (tv);
192 return 0;
193 default:
194 errno = EINVAL;
195 return -1;
196 }
197}
198
199/* time_t value in terms of stabilised absolute time.
200 * replacement for POSIX time()
201 */
202time_t
203quagga_time (time_t *t)
204{
205 struct timeval tv;
206 quagga_real_stabilised (&tv);
207 if (t)
208 *t = tv.tv_sec;
209 return tv.tv_sec;
210}
211
212/* Public export of recent_relative_time by value */
213struct timeval
214recent_relative_time (void)
215{
216 return relative_time;
217}
218
paula48b4e62005-04-22 00:43:47 +0000219static unsigned int
paule04ab742003-01-17 23:47:00 +0000220cpu_record_hash_key (struct cpu_thread_history *a)
221{
paul8cc41982005-05-06 21:25:49 +0000222 return (uintptr_t) a->func;
paule04ab742003-01-17 23:47:00 +0000223}
224
225static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100226cpu_record_hash_cmp (const struct cpu_thread_history *a,
227 const struct cpu_thread_history *b)
paule04ab742003-01-17 23:47:00 +0000228{
229 return a->func == b->func;
230}
231
paul8cc41982005-05-06 21:25:49 +0000232static void *
paule04ab742003-01-17 23:47:00 +0000233cpu_record_hash_alloc (struct cpu_thread_history *a)
234{
235 struct cpu_thread_history *new;
paul039b9572004-10-31 16:43:17 +0000236 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
paule04ab742003-01-17 23:47:00 +0000237 new->func = a->func;
paul9d11a192004-10-31 16:19:24 +0000238 new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);
paule04ab742003-01-17 23:47:00 +0000239 return new;
240}
241
Chris Caputo228da422009-07-18 05:44:03 +0000242static void
243cpu_record_hash_free (void *a)
244{
245 struct cpu_thread_history *hist = a;
246
247 XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname);
248 XFREE (MTYPE_THREAD_STATS, hist);
249}
250
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100251static void
paule04ab742003-01-17 23:47:00 +0000252vty_out_cpu_thread_history(struct vty* vty,
253 struct cpu_thread_history *a)
254{
ajs8b70d0b2005-04-28 01:31:13 +0000255#ifdef HAVE_RUSAGE
256 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
257 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
258 a->cpu.total/a->total_calls, a->cpu.max,
259 a->real.total/a->total_calls, a->real.max);
260#else
261 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
262 a->real.total/1000, a->real.total%1000, a->total_calls,
263 a->real.total/a->total_calls, a->real.max);
264#endif
265 vty_out(vty, " %c%c%c%c%c%c %s%s",
paule04ab742003-01-17 23:47:00 +0000266 a->types & (1 << THREAD_READ) ? 'R':' ',
267 a->types & (1 << THREAD_WRITE) ? 'W':' ',
268 a->types & (1 << THREAD_TIMER) ? 'T':' ',
269 a->types & (1 << THREAD_EVENT) ? 'E':' ',
270 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
paula48b4e62005-04-22 00:43:47 +0000271 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
paule04ab742003-01-17 23:47:00 +0000272 a->funcname, VTY_NEWLINE);
273}
274
275static void
276cpu_record_hash_print(struct hash_backet *bucket,
277 void *args[])
278{
279 struct cpu_thread_history *totals = args[0];
280 struct vty *vty = args[1];
Paul Jakma41b23732009-06-30 16:12:49 +0100281 thread_type *filter = args[2];
paule04ab742003-01-17 23:47:00 +0000282 struct cpu_thread_history *a = bucket->data;
paula48b4e62005-04-22 00:43:47 +0000283
paule04ab742003-01-17 23:47:00 +0000284 a = bucket->data;
285 if ( !(a->types & *filter) )
286 return;
287 vty_out_cpu_thread_history(vty,a);
paule04ab742003-01-17 23:47:00 +0000288 totals->total_calls += a->total_calls;
ajs8b70d0b2005-04-28 01:31:13 +0000289 totals->real.total += a->real.total;
290 if (totals->real.max < a->real.max)
291 totals->real.max = a->real.max;
292#ifdef HAVE_RUSAGE
293 totals->cpu.total += a->cpu.total;
294 if (totals->cpu.max < a->cpu.max)
295 totals->cpu.max = a->cpu.max;
296#endif
paule04ab742003-01-17 23:47:00 +0000297}
298
299static void
Paul Jakma41b23732009-06-30 16:12:49 +0100300cpu_record_print(struct vty *vty, thread_type filter)
paule04ab742003-01-17 23:47:00 +0000301{
302 struct cpu_thread_history tmp;
303 void *args[3] = {&tmp, vty, &filter};
304
305 memset(&tmp, 0, sizeof tmp);
Paul Jakma85261002010-01-11 16:30:45 +0000306 tmp.funcname = (char *)"TOTAL";
paule04ab742003-01-17 23:47:00 +0000307 tmp.types = filter;
308
ajs8b70d0b2005-04-28 01:31:13 +0000309#ifdef HAVE_RUSAGE
310 vty_out(vty, "%21s %18s %18s%s",
311 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
312#endif
313 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
314#ifdef HAVE_RUSAGE
315 vty_out(vty, " Avg uSec Max uSecs");
316#endif
317 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
paule04ab742003-01-17 23:47:00 +0000318 hash_iterate(cpu_record,
319 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
320 args);
321
322 if (tmp.total_calls > 0)
323 vty_out_cpu_thread_history(vty, &tmp);
324}
325
326DEFUN(show_thread_cpu,
327 show_thread_cpu_cmd,
328 "show thread cpu [FILTER]",
329 SHOW_STR
330 "Thread information\n"
331 "Thread CPU usage\n"
paula48b4e62005-04-22 00:43:47 +0000332 "Display filter (rwtexb)\n")
paule04ab742003-01-17 23:47:00 +0000333{
334 int i = 0;
Paul Jakma41b23732009-06-30 16:12:49 +0100335 thread_type filter = (thread_type) -1U;
paule04ab742003-01-17 23:47:00 +0000336
337 if (argc > 0)
338 {
339 filter = 0;
340 while (argv[0][i] != '\0')
341 {
342 switch ( argv[0][i] )
343 {
344 case 'r':
345 case 'R':
346 filter |= (1 << THREAD_READ);
347 break;
348 case 'w':
349 case 'W':
350 filter |= (1 << THREAD_WRITE);
351 break;
352 case 't':
353 case 'T':
354 filter |= (1 << THREAD_TIMER);
355 break;
356 case 'e':
357 case 'E':
358 filter |= (1 << THREAD_EVENT);
359 break;
360 case 'x':
361 case 'X':
362 filter |= (1 << THREAD_EXECUTE);
363 break;
paula48b4e62005-04-22 00:43:47 +0000364 case 'b':
365 case 'B':
366 filter |= (1 << THREAD_BACKGROUND);
367 break;
paule04ab742003-01-17 23:47:00 +0000368 default:
369 break;
370 }
371 ++i;
372 }
373 if (filter == 0)
374 {
paula48b4e62005-04-22 00:43:47 +0000375 vty_out(vty, "Invalid filter \"%s\" specified,"
376 " must contain at least one of 'RWTEXB'%s",
paule04ab742003-01-17 23:47:00 +0000377 argv[0], VTY_NEWLINE);
378 return CMD_WARNING;
379 }
380 }
381
382 cpu_record_print(vty, filter);
383 return CMD_SUCCESS;
384}
Paul Jakmae276eb82010-01-09 16:15:00 +0000385
386static void
387cpu_record_hash_clear (struct hash_backet *bucket,
388 void *args)
389{
390 thread_type *filter = args;
391 struct cpu_thread_history *a = bucket->data;
392
393 a = bucket->data;
394 if ( !(a->types & *filter) )
395 return;
396
397 hash_release (cpu_record, bucket->data);
398}
399
400static void
401cpu_record_clear (thread_type filter)
402{
403 thread_type *tmp = &filter;
404 hash_iterate (cpu_record,
405 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
406 tmp);
407}
408
409DEFUN(clear_thread_cpu,
410 clear_thread_cpu_cmd,
411 "clear thread cpu [FILTER]",
412 "Clear stored data\n"
413 "Thread information\n"
414 "Thread CPU usage\n"
415 "Display filter (rwtexb)\n")
416{
417 int i = 0;
418 thread_type filter = (thread_type) -1U;
419
420 if (argc > 0)
421 {
422 filter = 0;
423 while (argv[0][i] != '\0')
424 {
425 switch ( argv[0][i] )
426 {
427 case 'r':
428 case 'R':
429 filter |= (1 << THREAD_READ);
430 break;
431 case 'w':
432 case 'W':
433 filter |= (1 << THREAD_WRITE);
434 break;
435 case 't':
436 case 'T':
437 filter |= (1 << THREAD_TIMER);
438 break;
439 case 'e':
440 case 'E':
441 filter |= (1 << THREAD_EVENT);
442 break;
443 case 'x':
444 case 'X':
445 filter |= (1 << THREAD_EXECUTE);
446 break;
447 case 'b':
448 case 'B':
449 filter |= (1 << THREAD_BACKGROUND);
450 break;
451 default:
452 break;
453 }
454 ++i;
455 }
456 if (filter == 0)
457 {
458 vty_out(vty, "Invalid filter \"%s\" specified,"
459 " must contain at least one of 'RWTEXB'%s",
460 argv[0], VTY_NEWLINE);
461 return CMD_WARNING;
462 }
463 }
464
465 cpu_record_clear (filter);
466 return CMD_SUCCESS;
467}
paule04ab742003-01-17 23:47:00 +0000468
paul718e3742002-12-13 20:15:29 +0000469/* List allocation and head/tail print out. */
470static void
471thread_list_debug (struct thread_list *list)
472{
473 printf ("count [%d] head [%p] tail [%p]\n",
474 list->count, list->head, list->tail);
475}
476
477/* Debug print for thread_master. */
paul8cc41982005-05-06 21:25:49 +0000478static void __attribute__ ((unused))
paul718e3742002-12-13 20:15:29 +0000479thread_master_debug (struct thread_master *m)
480{
481 printf ("-----------\n");
482 printf ("readlist : ");
483 thread_list_debug (&m->read);
484 printf ("writelist : ");
485 thread_list_debug (&m->write);
486 printf ("timerlist : ");
487 thread_list_debug (&m->timer);
488 printf ("eventlist : ");
489 thread_list_debug (&m->event);
490 printf ("unuselist : ");
491 thread_list_debug (&m->unuse);
paula48b4e62005-04-22 00:43:47 +0000492 printf ("bgndlist : ");
493 thread_list_debug (&m->background);
paul718e3742002-12-13 20:15:29 +0000494 printf ("total alloc: [%ld]\n", m->alloc);
495 printf ("-----------\n");
496}
497
498/* Allocate new thread master. */
499struct thread_master *
500thread_master_create ()
501{
paule04ab742003-01-17 23:47:00 +0000502 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000503 cpu_record
504 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100505 (int (*) (const void *, const void *))cpu_record_hash_cmp);
paula48b4e62005-04-22 00:43:47 +0000506
paul718e3742002-12-13 20:15:29 +0000507 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
508 sizeof (struct thread_master));
509}
510
511/* Add a new thread to the list. */
512static void
513thread_list_add (struct thread_list *list, struct thread *thread)
514{
515 thread->next = NULL;
516 thread->prev = list->tail;
517 if (list->tail)
518 list->tail->next = thread;
519 else
520 list->head = thread;
521 list->tail = thread;
522 list->count++;
523}
524
525/* Add a new thread just before the point. */
526static void
527thread_list_add_before (struct thread_list *list,
528 struct thread *point,
529 struct thread *thread)
530{
531 thread->next = point;
532 thread->prev = point->prev;
533 if (point->prev)
534 point->prev->next = thread;
535 else
536 list->head = thread;
537 point->prev = thread;
538 list->count++;
539}
540
541/* Delete a thread from the list. */
542static struct thread *
543thread_list_delete (struct thread_list *list, struct thread *thread)
544{
545 if (thread->next)
546 thread->next->prev = thread->prev;
547 else
548 list->tail = thread->prev;
549 if (thread->prev)
550 thread->prev->next = thread->next;
551 else
552 list->head = thread->next;
553 thread->next = thread->prev = NULL;
554 list->count--;
555 return thread;
556}
557
558/* Move thread to unuse list. */
559static void
560thread_add_unuse (struct thread_master *m, struct thread *thread)
561{
paula48b4e62005-04-22 00:43:47 +0000562 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000563 assert (thread->next == NULL);
564 assert (thread->prev == NULL);
565 assert (thread->type == THREAD_UNUSED);
566 thread_list_add (&m->unuse, thread);
paul9d11a192004-10-31 16:19:24 +0000567 /* XXX: Should we deallocate funcname here? */
paul718e3742002-12-13 20:15:29 +0000568}
569
570/* Free all unused thread. */
571static void
572thread_list_free (struct thread_master *m, struct thread_list *list)
573{
574 struct thread *t;
575 struct thread *next;
576
577 for (t = list->head; t; t = next)
578 {
579 next = t->next;
Chris Caputo228da422009-07-18 05:44:03 +0000580 if (t->funcname)
581 XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);
paul718e3742002-12-13 20:15:29 +0000582 XFREE (MTYPE_THREAD, t);
583 list->count--;
584 m->alloc--;
585 }
586}
587
588/* Stop thread scheduler. */
589void
590thread_master_free (struct thread_master *m)
591{
592 thread_list_free (m, &m->read);
593 thread_list_free (m, &m->write);
594 thread_list_free (m, &m->timer);
595 thread_list_free (m, &m->event);
596 thread_list_free (m, &m->ready);
597 thread_list_free (m, &m->unuse);
paula48b4e62005-04-22 00:43:47 +0000598 thread_list_free (m, &m->background);
599
paul718e3742002-12-13 20:15:29 +0000600 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000601
602 if (cpu_record)
603 {
604 hash_clean (cpu_record, cpu_record_hash_free);
605 hash_free (cpu_record);
606 cpu_record = NULL;
607 }
paul718e3742002-12-13 20:15:29 +0000608}
609
paul8cc41982005-05-06 21:25:49 +0000610/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100611static int
paul8cc41982005-05-06 21:25:49 +0000612thread_empty (struct thread_list *list)
613{
614 return list->head ? 0 : 1;
615}
616
paul718e3742002-12-13 20:15:29 +0000617/* Delete top of the list and return it. */
618static struct thread *
619thread_trim_head (struct thread_list *list)
620{
paul8cc41982005-05-06 21:25:49 +0000621 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000622 return thread_list_delete (list, list->head);
623 return NULL;
624}
625
paul718e3742002-12-13 20:15:29 +0000626/* Return remain time in second. */
627unsigned long
628thread_timer_remain_second (struct thread *thread)
629{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000630 quagga_get_relative (NULL);
631
632 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
633 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000634 else
635 return 0;
636}
637
paule04ab742003-01-17 23:47:00 +0000638/* Trim blankspace and "()"s */
639static char *
hasso8c328f12004-10-05 21:01:23 +0000640strip_funcname (const char *funcname)
paule04ab742003-01-17 23:47:00 +0000641{
642 char buff[100];
643 char tmp, *ret, *e, *b = buff;
644
645 strncpy(buff, funcname, sizeof(buff));
646 buff[ sizeof(buff) -1] = '\0';
647 e = buff +strlen(buff) -1;
648
649 /* Wont work for funcname == "Word (explanation)" */
650
651 while (*b == ' ' || *b == '(')
652 ++b;
653 while (*e == ' ' || *e == ')')
654 --e;
655 e++;
656
657 tmp = *e;
658 *e = '\0';
paul9d11a192004-10-31 16:19:24 +0000659 ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b);
paule04ab742003-01-17 23:47:00 +0000660 *e = tmp;
661
662 return ret;
663}
664
paul718e3742002-12-13 20:15:29 +0000665/* Get new thread. */
666static struct thread *
667thread_get (struct thread_master *m, u_char type,
hasso8c328f12004-10-05 21:01:23 +0000668 int (*func) (struct thread *), void *arg, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000669{
670 struct thread *thread;
671
paul8cc41982005-05-06 21:25:49 +0000672 if (!thread_empty (&m->unuse))
paul2946f652003-03-27 23:48:24 +0000673 {
674 thread = thread_trim_head (&m->unuse);
675 if (thread->funcname)
paul9d11a192004-10-31 16:19:24 +0000676 XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);
paul2946f652003-03-27 23:48:24 +0000677 }
paul718e3742002-12-13 20:15:29 +0000678 else
679 {
680 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
681 m->alloc++;
682 }
683 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000684 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000685 thread->master = m;
686 thread->func = func;
687 thread->arg = arg;
688
paule04ab742003-01-17 23:47:00 +0000689 thread->funcname = strip_funcname(funcname);
690
paul718e3742002-12-13 20:15:29 +0000691 return thread;
692}
693
694/* Add new read thread. */
695struct thread *
paule04ab742003-01-17 23:47:00 +0000696funcname_thread_add_read (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000697 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000698{
699 struct thread *thread;
700
701 assert (m != NULL);
702
703 if (FD_ISSET (fd, &m->readfd))
704 {
705 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
706 return NULL;
707 }
708
paule04ab742003-01-17 23:47:00 +0000709 thread = thread_get (m, THREAD_READ, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000710 FD_SET (fd, &m->readfd);
711 thread->u.fd = fd;
712 thread_list_add (&m->read, thread);
713
714 return thread;
715}
716
717/* Add new write thread. */
718struct thread *
paule04ab742003-01-17 23:47:00 +0000719funcname_thread_add_write (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000720 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000721{
722 struct thread *thread;
723
724 assert (m != NULL);
725
726 if (FD_ISSET (fd, &m->writefd))
727 {
728 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
729 return NULL;
730 }
731
paule04ab742003-01-17 23:47:00 +0000732 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000733 FD_SET (fd, &m->writefd);
734 thread->u.fd = fd;
735 thread_list_add (&m->write, thread);
736
737 return thread;
738}
739
paul98c91ac2004-10-05 14:57:50 +0000740static struct thread *
741funcname_thread_add_timer_timeval (struct thread_master *m,
742 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000743 int type,
paul98c91ac2004-10-05 14:57:50 +0000744 void *arg,
745 struct timeval *time_relative,
hasso8c328f12004-10-05 21:01:23 +0000746 const char* funcname)
paul718e3742002-12-13 20:15:29 +0000747{
paul718e3742002-12-13 20:15:29 +0000748 struct thread *thread;
paula48b4e62005-04-22 00:43:47 +0000749 struct thread_list *list;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000750 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000751 struct thread *tt;
paul718e3742002-12-13 20:15:29 +0000752
753 assert (m != NULL);
754
ajs8b70d0b2005-04-28 01:31:13 +0000755 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000756 assert (time_relative);
757
ajs8b70d0b2005-04-28 01:31:13 +0000758 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
paula48b4e62005-04-22 00:43:47 +0000759 thread = thread_get (m, type, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000760
761 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100762 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000763 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
764 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000765 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000766
767 /* Sort by timeval. */
paula48b4e62005-04-22 00:43:47 +0000768 for (tt = list->head; tt; tt = tt->next)
paul718e3742002-12-13 20:15:29 +0000769 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
770 break;
771
772 if (tt)
paula48b4e62005-04-22 00:43:47 +0000773 thread_list_add_before (list, tt, thread);
paul718e3742002-12-13 20:15:29 +0000774 else
paula48b4e62005-04-22 00:43:47 +0000775 thread_list_add (list, thread);
paul718e3742002-12-13 20:15:29 +0000776
777 return thread;
778}
779
paul98c91ac2004-10-05 14:57:50 +0000780
781/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000782struct thread *
paul98c91ac2004-10-05 14:57:50 +0000783funcname_thread_add_timer (struct thread_master *m,
784 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000785 void *arg, long timer, const char* funcname)
jardin9e867fe2003-12-23 08:56:18 +0000786{
paul98c91ac2004-10-05 14:57:50 +0000787 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000788
789 assert (m != NULL);
790
paul9076fbd2004-10-11 09:40:58 +0000791 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000792 trel.tv_usec = 0;
793
paula48b4e62005-04-22 00:43:47 +0000794 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
795 &trel, funcname);
paul98c91ac2004-10-05 14:57:50 +0000796}
797
798/* Add timer event thread with "millisecond" resolution */
799struct thread *
800funcname_thread_add_timer_msec (struct thread_master *m,
801 int (*func) (struct thread *),
hasso8c328f12004-10-05 21:01:23 +0000802 void *arg, long timer, const char* funcname)
paul98c91ac2004-10-05 14:57:50 +0000803{
804 struct timeval trel;
805
806 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000807
ajsaf04bd72004-12-28 17:00:12 +0000808 trel.tv_sec = timer / 1000;
809 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000810
paula48b4e62005-04-22 00:43:47 +0000811 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
812 arg, &trel, funcname);
813}
814
815/* Add a background thread, with an optional millisec delay */
816struct thread *
817funcname_thread_add_background (struct thread_master *m,
818 int (*func) (struct thread *),
819 void *arg, long delay,
820 const char *funcname)
821{
822 struct timeval trel;
823
824 assert (m != NULL);
825
826 if (delay)
827 {
828 trel.tv_sec = delay / 1000;
829 trel.tv_usec = 1000*(delay % 1000);
830 }
831 else
832 {
833 trel.tv_sec = 0;
834 trel.tv_usec = 0;
835 }
836
837 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
838 arg, &trel, funcname);
jardin9e867fe2003-12-23 08:56:18 +0000839}
840
paul718e3742002-12-13 20:15:29 +0000841/* Add simple event thread. */
842struct thread *
paule04ab742003-01-17 23:47:00 +0000843funcname_thread_add_event (struct thread_master *m,
hasso8c328f12004-10-05 21:01:23 +0000844 int (*func) (struct thread *), void *arg, int val, const char* funcname)
paul718e3742002-12-13 20:15:29 +0000845{
846 struct thread *thread;
847
848 assert (m != NULL);
849
paule04ab742003-01-17 23:47:00 +0000850 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
paul718e3742002-12-13 20:15:29 +0000851 thread->u.val = val;
852 thread_list_add (&m->event, thread);
853
854 return thread;
855}
856
857/* Cancel thread from scheduler. */
858void
859thread_cancel (struct thread *thread)
860{
paula48b4e62005-04-22 00:43:47 +0000861 struct thread_list *list;
862
paul718e3742002-12-13 20:15:29 +0000863 switch (thread->type)
864 {
865 case THREAD_READ:
866 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
867 FD_CLR (thread->u.fd, &thread->master->readfd);
paula48b4e62005-04-22 00:43:47 +0000868 list = &thread->master->read;
paul718e3742002-12-13 20:15:29 +0000869 break;
870 case THREAD_WRITE:
871 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
872 FD_CLR (thread->u.fd, &thread->master->writefd);
paula48b4e62005-04-22 00:43:47 +0000873 list = &thread->master->write;
paul718e3742002-12-13 20:15:29 +0000874 break;
875 case THREAD_TIMER:
paula48b4e62005-04-22 00:43:47 +0000876 list = &thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000877 break;
878 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000879 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000880 break;
881 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000882 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000883 break;
paula48b4e62005-04-22 00:43:47 +0000884 case THREAD_BACKGROUND:
885 list = &thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000886 break;
paul718e3742002-12-13 20:15:29 +0000887 default:
paula48b4e62005-04-22 00:43:47 +0000888 return;
paul718e3742002-12-13 20:15:29 +0000889 break;
890 }
paula48b4e62005-04-22 00:43:47 +0000891 thread_list_delete (list, thread);
paul718e3742002-12-13 20:15:29 +0000892 thread->type = THREAD_UNUSED;
893 thread_add_unuse (thread->master, thread);
894}
895
896/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +0000897unsigned int
paul718e3742002-12-13 20:15:29 +0000898thread_cancel_event (struct thread_master *m, void *arg)
899{
pauldc818072005-05-19 01:30:53 +0000900 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +0000901 struct thread *thread;
902
903 thread = m->event.head;
904 while (thread)
905 {
906 struct thread *t;
907
908 t = thread;
909 thread = t->next;
910
911 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +0000912 {
pauldc818072005-05-19 01:30:53 +0000913 ret++;
paula48b4e62005-04-22 00:43:47 +0000914 thread_list_delete (&m->event, t);
915 t->type = THREAD_UNUSED;
916 thread_add_unuse (m, t);
917 }
paul718e3742002-12-13 20:15:29 +0000918 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +0000919
920 /* thread can be on the ready list too */
921 thread = m->ready.head;
922 while (thread)
923 {
924 struct thread *t;
925
926 t = thread;
927 thread = t->next;
928
929 if (t->arg == arg)
930 {
931 ret++;
932 thread_list_delete (&m->ready, t);
933 t->type = THREAD_UNUSED;
934 thread_add_unuse (m, t);
935 }
936 }
pauldc818072005-05-19 01:30:53 +0000937 return ret;
paul718e3742002-12-13 20:15:29 +0000938}
939
paula48b4e62005-04-22 00:43:47 +0000940static struct timeval *
941thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +0000942{
paul8cc41982005-05-06 21:25:49 +0000943 if (!thread_empty (tlist))
paul718e3742002-12-13 20:15:29 +0000944 {
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000945 *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +0000946 return timer_val;
947 }
948 return NULL;
949}
paul718e3742002-12-13 20:15:29 +0000950
paul8cc41982005-05-06 21:25:49 +0000951static struct thread *
paul718e3742002-12-13 20:15:29 +0000952thread_run (struct thread_master *m, struct thread *thread,
953 struct thread *fetch)
954{
955 *fetch = *thread;
956 thread->type = THREAD_UNUSED;
Chris Caputo228da422009-07-18 05:44:03 +0000957 thread->funcname = NULL; /* thread_call will free fetch's copied pointer */
paul718e3742002-12-13 20:15:29 +0000958 thread_add_unuse (m, thread);
959 return fetch;
960}
961
paula48b4e62005-04-22 00:43:47 +0000962static int
963thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
paul718e3742002-12-13 20:15:29 +0000964{
965 struct thread *thread;
966 struct thread *next;
967 int ready = 0;
paula48b4e62005-04-22 00:43:47 +0000968
969 assert (list);
970
paul718e3742002-12-13 20:15:29 +0000971 for (thread = list->head; thread; thread = next)
972 {
973 next = thread->next;
974
975 if (FD_ISSET (THREAD_FD (thread), fdset))
paula48b4e62005-04-22 00:43:47 +0000976 {
977 assert (FD_ISSET (THREAD_FD (thread), mfdset));
978 FD_CLR(THREAD_FD (thread), mfdset);
979 thread_list_delete (list, thread);
980 thread_list_add (&thread->master->ready, thread);
981 thread->type = THREAD_READY;
982 ready++;
983 }
paul718e3742002-12-13 20:15:29 +0000984 }
985 return ready;
986}
987
ajs8b70d0b2005-04-28 01:31:13 +0000988/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +0000989static unsigned int
990thread_timer_process (struct thread_list *list, struct timeval *timenow)
991{
992 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +0000993 struct thread *next;
paula48b4e62005-04-22 00:43:47 +0000994 unsigned int ready = 0;
995
Paul Jakmab5043aa2012-02-28 18:32:56 +0000996 for (thread = list->head; thread; thread = next)
ajs8b70d0b2005-04-28 01:31:13 +0000997 {
Paul Jakmab5043aa2012-02-28 18:32:56 +0000998 next = thread->next;
ajs8b70d0b2005-04-28 01:31:13 +0000999 if (timeval_cmp (*timenow, thread->u.sands) < 0)
1000 return ready;
1001 thread_list_delete (list, thread);
1002 thread->type = THREAD_READY;
1003 thread_list_add (&thread->master->ready, thread);
1004 ready++;
1005 }
paula48b4e62005-04-22 00:43:47 +00001006 return ready;
1007}
1008
Paul Jakma2613abe2010-01-11 16:33:07 +00001009/* process a list en masse, e.g. for event thread lists */
1010static unsigned int
1011thread_process (struct thread_list *list)
1012{
1013 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001014 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001015 unsigned int ready = 0;
1016
Paul Jakmab5043aa2012-02-28 18:32:56 +00001017 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001018 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001019 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001020 thread_list_delete (list, thread);
1021 thread->type = THREAD_READY;
1022 thread_list_add (&thread->master->ready, thread);
1023 ready++;
1024 }
1025 return ready;
1026}
1027
1028
paul718e3742002-12-13 20:15:29 +00001029/* Fetch next ready thread. */
1030struct thread *
1031thread_fetch (struct thread_master *m, struct thread *fetch)
1032{
paul718e3742002-12-13 20:15:29 +00001033 struct thread *thread;
1034 fd_set readfd;
1035 fd_set writefd;
1036 fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001037 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001038 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001039 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001040 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001041
1042 while (1)
1043 {
paula48b4e62005-04-22 00:43:47 +00001044 int num = 0;
paula48b4e62005-04-22 00:43:47 +00001045
Paul Jakma2613abe2010-01-11 16:33:07 +00001046 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001047 quagga_sigevent_process ();
1048
Paul Jakma2613abe2010-01-11 16:33:07 +00001049 /* Drain the ready queue of already scheduled jobs, before scheduling
1050 * more.
paula48b4e62005-04-22 00:43:47 +00001051 */
paul718e3742002-12-13 20:15:29 +00001052 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001053 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001054
Paul Jakma2613abe2010-01-11 16:33:07 +00001055 /* To be fair to all kinds of threads, and avoid starvation, we
1056 * need to be careful to consider all thread types for scheduling
1057 * in each quanta. I.e. we should not return early from here on.
1058 */
1059
1060 /* Normal event are the next highest priority. */
1061 thread_process (&m->event);
1062
paul718e3742002-12-13 20:15:29 +00001063 /* Structure copy. */
1064 readfd = m->readfd;
1065 writefd = m->writefd;
1066 exceptfd = m->exceptfd;
paula48b4e62005-04-22 00:43:47 +00001067
1068 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001069 if (m->ready.count == 0)
1070 {
1071 quagga_get_relative (NULL);
1072 timer_wait = thread_timer_wait (&m->timer, &timer_val);
1073 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
1074
1075 if (timer_wait_bg &&
1076 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1077 timer_wait = timer_wait_bg;
1078 }
paula48b4e62005-04-22 00:43:47 +00001079
paul718e3742002-12-13 20:15:29 +00001080 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001081
1082 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001083 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001084 {
1085 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001086 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001087 zlog_warn ("select() error: %s", safe_strerror (errno));
paul05c447d2004-07-22 19:14:27 +00001088 return NULL;
1089 }
ajs8b70d0b2005-04-28 01:31:13 +00001090
1091 /* Check foreground timers. Historically, they have had higher
1092 priority than I/O threads, so let's push them onto the ready
1093 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001094 quagga_get_relative (NULL);
1095 thread_timer_process (&m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001096
1097 /* Got IO, process it */
1098 if (num > 0)
1099 {
1100 /* Normal priority read thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001101 thread_process_fd (&m->read, &readfd, &m->readfd);
paula48b4e62005-04-22 00:43:47 +00001102 /* Write thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001103 thread_process_fd (&m->write, &writefd, &m->writefd);
paula48b4e62005-04-22 00:43:47 +00001104 }
ajs8b70d0b2005-04-28 01:31:13 +00001105
1106#if 0
1107 /* If any threads were made ready above (I/O or foreground timer),
1108 perhaps we should avoid adding background timers to the ready
1109 list at this time. If this is code is uncommented, then background
1110 timer threads will not run unless there is nothing else to do. */
1111 if ((thread = thread_trim_head (&m->ready)) != NULL)
1112 return thread_run (m, thread, fetch);
1113#endif
1114
paula48b4e62005-04-22 00:43:47 +00001115 /* Background timer/events, lowest priority */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001116 thread_timer_process (&m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001117
ajs8b70d0b2005-04-28 01:31:13 +00001118 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001119 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001120 }
1121}
1122
ajs924b9222005-04-16 17:11:24 +00001123unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001124thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001125{
paul718e3742002-12-13 20:15:29 +00001126#ifdef HAVE_RUSAGE
1127 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001128 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1129 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001130#else
ajs8b70d0b2005-04-28 01:31:13 +00001131 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001132#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001133 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001134}
1135
ajs8b70d0b2005-04-28 01:31:13 +00001136/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1137 Note: we are using real (wall clock) time for this calculation.
1138 It could be argued that CPU time may make more sense in certain
1139 contexts. The things to consider are whether the thread may have
1140 blocked (in which case wall time increases, but CPU time does not),
1141 or whether the system is heavily loaded with other processes competing
1142 for CPU time. On balance, wall clock time seems to make sense.
1143 Plus it has the added benefit that gettimeofday should be faster
1144 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001145int
1146thread_should_yield (struct thread *thread)
1147{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001148 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001149 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001150 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001151}
1152
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001153void
1154thread_getrusage (RUSAGE_T *r)
1155{
1156 quagga_get_relative (NULL);
1157#ifdef HAVE_RUSAGE
1158 getrusage(RUSAGE_SELF, &(r->cpu));
1159#endif
1160 r->real = relative_time;
1161
1162#ifdef HAVE_CLOCK_MONOTONIC
1163 /* quagga_get_relative() only updates recent_time if gettimeofday
1164 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1165 * and guarantee to update it before threads are run...
1166 */
1167 quagga_gettimeofday(&recent_time);
1168#endif /* HAVE_CLOCK_MONOTONIC */
1169}
1170
paul718e3742002-12-13 20:15:29 +00001171/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001172 use that to get in-depth stats on the performance of the thread in addition
1173 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001174void
1175thread_call (struct thread *thread)
1176{
ajs8b70d0b2005-04-28 01:31:13 +00001177 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001178 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001179
1180 /* Cache a pointer to the relevant cpu history thread, if the thread
1181 * does not have it yet.
1182 *
1183 * Callers submitting 'dummy threads' hence must take care that
1184 * thread->cpu is NULL
1185 */
1186 if (!thread->hist)
1187 {
1188 struct cpu_thread_history tmp;
1189
1190 tmp.func = thread->func;
1191 tmp.funcname = thread->funcname;
1192
1193 thread->hist = hash_get (cpu_record, &tmp,
1194 (void * (*) (void *))cpu_record_hash_alloc);
1195 }
paul718e3742002-12-13 20:15:29 +00001196
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001197 GETRUSAGE (&before);
1198 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001199
1200 (*thread->func) (thread);
1201
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001202 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001203
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001204 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001205 thread->hist->real.total += realtime;
1206 if (thread->hist->real.max < realtime)
1207 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001208#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001209 thread->hist->cpu.total += cputime;
1210 if (thread->hist->cpu.max < cputime)
1211 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001212#endif
paule04ab742003-01-17 23:47:00 +00001213
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001214 ++(thread->hist->total_calls);
1215 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001216
ajs924b9222005-04-16 17:11:24 +00001217#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001218 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001219 {
1220 /*
1221 * We have a CPU Hog on our hands.
1222 * Whinge about it now, so we're aware this is yet another task
1223 * to fix.
1224 */
ajs8b70d0b2005-04-28 01:31:13 +00001225 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001226 thread->funcname,
1227 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001228 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001229 }
ajs924b9222005-04-16 17:11:24 +00001230#endif /* CONSUMED_TIME_CHECK */
Chris Caputo228da422009-07-18 05:44:03 +00001231
1232 XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname);
paul718e3742002-12-13 20:15:29 +00001233}
1234
1235/* Execute thread */
1236struct thread *
paule04ab742003-01-17 23:47:00 +00001237funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001238 int (*func)(struct thread *),
1239 void *arg,
paule04ab742003-01-17 23:47:00 +00001240 int val,
hasso8c328f12004-10-05 21:01:23 +00001241 const char* funcname)
paul718e3742002-12-13 20:15:29 +00001242{
1243 struct thread dummy;
1244
1245 memset (&dummy, 0, sizeof (struct thread));
1246
1247 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001248 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001249 dummy.master = NULL;
1250 dummy.func = func;
1251 dummy.arg = arg;
1252 dummy.u.val = val;
paule04ab742003-01-17 23:47:00 +00001253 dummy.funcname = strip_funcname (funcname);
paul718e3742002-12-13 20:15:29 +00001254 thread_call (&dummy);
1255
paul9d11a192004-10-31 16:19:24 +00001256 XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);
paul2946f652003-03-27 23:48:24 +00001257
paul718e3742002-12-13 20:15:29 +00001258 return NULL;
1259}