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