Annotation of embedaddon/quagga/lib/thread.c, revision 1.1.1.3
1.1 misho 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 "command.h"
31: #include "sigevent.h"
1.1.1.3 ! misho 32:
! 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:
! 39: extern int agentx_enabled;
! 40: #endif
! 41:
! 42: #if defined(__APPLE__)
! 43: #include <mach/mach.h>
! 44: #include <mach/mach_time.h>
! 45: #endif
! 46:
1.1 misho 47:
48: /* Recent absolute time of day */
49: struct timeval recent_time;
50: static struct timeval last_recent_time;
51: /* Relative time, since startup */
52: static struct timeval relative_time;
53: static struct timeval relative_time_base;
54: /* init flag */
55: static unsigned short timers_inited;
56:
57: static struct hash *cpu_record = NULL;
58:
59: /* Struct timeval's tv_usec one second value. */
60: #define TIMER_SECOND_MICRO 1000000L
61:
62: /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
63: And change negative values to 0. */
64: static struct timeval
65: timeval_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)
80: /* Change negative timeouts to 0. */
81: a.tv_sec = a.tv_usec = 0;
82:
83: return a;
84: }
85:
86: static struct timeval
87: timeval_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:
97: static long
98: timeval_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:
104: static unsigned long
105: timeval_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:
1.1.1.3 ! misho 111: #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
1.1 misho 112: static void
113: quagga_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: }
1.1.1.3 ! misho 130: #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
1.1 misho 131:
132: /* gettimeofday wrapper, to keep recent_time updated */
133: static int
134: quagga_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:
156: static int
157: quagga_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: }
1.1.1.3 ! misho 170: #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__ */
1.1 misho 187: 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: */
200: static void
201: quagga_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: */
212: int
213: quagga_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: */
233: time_t
234: quagga_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 */
244: struct timeval
245: recent_relative_time (void)
246: {
247: return relative_time;
248: }
249:
250: static unsigned int
251: cpu_record_hash_key (struct cpu_thread_history *a)
252: {
253: return (uintptr_t) a->func;
254: }
255:
256: static int
257: cpu_record_hash_cmp (const struct cpu_thread_history *a,
258: const struct cpu_thread_history *b)
259: {
260: return a->func == b->func;
261: }
262:
263: static void *
264: cpu_record_hash_alloc (struct cpu_thread_history *a)
265: {
266: struct cpu_thread_history *new;
267: new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
268: new->func = a->func;
1.1.1.3 ! misho 269: strcpy(new->funcname, a->funcname);
1.1 misho 270: return new;
271: }
272:
273: static void
274: cpu_record_hash_free (void *a)
275: {
276: struct cpu_thread_history *hist = a;
277:
278: XFREE (MTYPE_THREAD_STATS, hist);
279: }
280:
1.1.1.2 misho 281: static void
1.1 misho 282: vty_out_cpu_thread_history(struct vty* vty,
283: struct cpu_thread_history *a)
284: {
285: #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",
296: 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':' ',
301: a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
302: a->funcname, VTY_NEWLINE);
303: }
304:
305: static void
306: cpu_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];
311: thread_type *filter = args[2];
312: struct cpu_thread_history *a = bucket->data;
313:
314: a = bucket->data;
315: if ( !(a->types & *filter) )
316: return;
317: vty_out_cpu_thread_history(vty,a);
318: totals->total_calls += a->total_calls;
319: 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
327: }
328:
329: static void
330: cpu_record_print(struct vty *vty, thread_type filter)
331: {
332: struct cpu_thread_history tmp;
333: void *args[3] = {&tmp, vty, &filter};
334:
335: memset(&tmp, 0, sizeof tmp);
1.1.1.3 ! misho 336: strcpy(tmp.funcname, "TOTAL");
1.1 misho 337: tmp.types = filter;
338:
339: #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);
348: 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:
356: DEFUN(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"
362: "Display filter (rwtexb)\n")
363: {
364: int i = 0;
365: thread_type filter = (thread_type) -1U;
366:
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;
394: case 'b':
395: case 'B':
396: filter |= (1 << THREAD_BACKGROUND);
397: break;
398: default:
399: break;
400: }
401: ++i;
402: }
403: if (filter == 0)
404: {
405: vty_out(vty, "Invalid filter \"%s\" specified,"
406: " must contain at least one of 'RWTEXB'%s",
407: argv[0], VTY_NEWLINE);
408: return CMD_WARNING;
409: }
410: }
411:
412: cpu_record_print(vty, filter);
413: return CMD_SUCCESS;
414: }
415:
416: static void
417: cpu_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:
430: static void
431: cpu_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:
439: DEFUN(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: }
498:
499: /* List allocation and head/tail print out. */
500: static void
501: thread_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. */
508: static void __attribute__ ((unused))
509: thread_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);
522: printf ("bgndlist : ");
523: thread_list_debug (&m->background);
524: printf ("total alloc: [%ld]\n", m->alloc);
525: printf ("-----------\n");
526: }
527:
528: /* Allocate new thread master. */
529: struct thread_master *
530: thread_master_create ()
531: {
532: if (cpu_record == NULL)
533: cpu_record
534: = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
535: (int (*) (const void *, const void *))cpu_record_hash_cmp);
536:
537: return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
538: sizeof (struct thread_master));
539: }
540:
541: /* Add a new thread to the list. */
542: static void
543: thread_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. */
556: static void
557: thread_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. */
572: static struct thread *
573: thread_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. */
589: static void
590: thread_add_unuse (struct thread_master *m, struct thread *thread)
591: {
592: assert (m != NULL && thread != NULL);
593: assert (thread->next == NULL);
594: assert (thread->prev == NULL);
595: assert (thread->type == THREAD_UNUSED);
596: thread_list_add (&m->unuse, thread);
597: /* XXX: Should we deallocate funcname here? */
598: }
599:
600: /* Free all unused thread. */
601: static void
602: thread_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. */
617: void
618: thread_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);
626: thread_list_free (m, &m->background);
627:
628: XFREE (MTYPE_THREAD_MASTER, m);
629:
630: if (cpu_record)
631: {
632: hash_clean (cpu_record, cpu_record_hash_free);
633: hash_free (cpu_record);
634: cpu_record = NULL;
635: }
636: }
637:
638: /* Thread list is empty or not. */
1.1.1.2 misho 639: static int
1.1 misho 640: thread_empty (struct thread_list *list)
641: {
642: return list->head ? 0 : 1;
643: }
644:
645: /* Delete top of the list and return it. */
646: static struct thread *
647: thread_trim_head (struct thread_list *list)
648: {
649: if (!thread_empty (list))
650: return thread_list_delete (list, list->head);
651: return NULL;
652: }
653:
654: /* Return remain time in second. */
655: unsigned long
656: thread_timer_remain_second (struct thread *thread)
657: {
658: 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;
662: else
663: return 0;
664: }
665:
666: /* Trim blankspace and "()"s */
1.1.1.3 ! misho 667: void
! 668: strip_funcname (char *dest, const char *funcname)
1.1 misho 669: {
1.1.1.3 ! misho 670: char buff[FUNCNAME_LEN];
! 671: char tmp, *e, *b = buff;
1.1 misho 672:
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';
1.1.1.3 ! misho 687: strcpy (dest, b);
1.1 misho 688: *e = tmp;
689: }
690:
691: /* Get new thread. */
692: static struct thread *
693: thread_get (struct thread_master *m, u_char type,
694: int (*func) (struct thread *), void *arg, const char* funcname)
695: {
1.1.1.3 ! misho 696: struct thread *thread = thread_trim_head (&m->unuse);
1.1 misho 697:
1.1.1.3 ! misho 698: if (! thread)
1.1 misho 699: {
700: thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
701: m->alloc++;
702: }
703: thread->type = type;
704: thread->add_type = type;
705: thread->master = m;
706: thread->func = func;
707: thread->arg = arg;
708:
1.1.1.3 ! misho 709: strip_funcname (thread->funcname, funcname);
1.1 misho 710:
711: return thread;
712: }
713:
714: /* Add new read thread. */
715: struct thread *
716: funcname_thread_add_read (struct thread_master *m,
717: int (*func) (struct thread *), void *arg, int fd, const char* funcname)
718: {
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:
729: thread = thread_get (m, THREAD_READ, func, arg, funcname);
730: 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. */
738: struct thread *
739: funcname_thread_add_write (struct thread_master *m,
740: int (*func) (struct thread *), void *arg, int fd, const char* funcname)
741: {
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:
752: thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
753: FD_SET (fd, &m->writefd);
754: thread->u.fd = fd;
755: thread_list_add (&m->write, thread);
756:
757: return thread;
758: }
759:
760: static struct thread *
761: funcname_thread_add_timer_timeval (struct thread_master *m,
762: int (*func) (struct thread *),
763: int type,
764: void *arg,
765: struct timeval *time_relative,
766: const char* funcname)
767: {
768: struct thread *thread;
769: struct thread_list *list;
770: struct timeval alarm_time;
771: struct thread *tt;
772:
773: assert (m != NULL);
774:
775: assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
776: assert (time_relative);
777:
778: list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
779: thread = thread_get (m, type, func, arg, funcname);
780:
781: /* Do we need jitter here? */
782: quagga_get_relative (NULL);
783: 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;
785: thread->u.sands = timeval_adjust(alarm_time);
786:
787: /* Sort by timeval. */
788: for (tt = list->head; tt; tt = tt->next)
789: if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
790: break;
791:
792: if (tt)
793: thread_list_add_before (list, tt, thread);
794: else
795: thread_list_add (list, thread);
796:
797: return thread;
798: }
799:
800:
801: /* Add timer event thread. */
802: struct thread *
803: funcname_thread_add_timer (struct thread_master *m,
804: int (*func) (struct thread *),
805: void *arg, long timer, const char* funcname)
806: {
807: struct timeval trel;
808:
809: assert (m != NULL);
810:
811: trel.tv_sec = timer;
812: trel.tv_usec = 0;
813:
814: return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
815: &trel, funcname);
816: }
817:
818: /* Add timer event thread with "millisecond" resolution */
819: struct thread *
820: funcname_thread_add_timer_msec (struct thread_master *m,
821: int (*func) (struct thread *),
822: void *arg, long timer, const char* funcname)
823: {
824: struct timeval trel;
825:
826: assert (m != NULL);
827:
828: trel.tv_sec = timer / 1000;
829: trel.tv_usec = 1000*(timer % 1000);
830:
831: 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 */
836: struct thread *
837: funcname_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);
859: }
860:
861: /* Add simple event thread. */
862: struct thread *
863: funcname_thread_add_event (struct thread_master *m,
864: int (*func) (struct thread *), void *arg, int val, const char* funcname)
865: {
866: struct thread *thread;
867:
868: assert (m != NULL);
869:
870: thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
871: thread->u.val = val;
872: thread_list_add (&m->event, thread);
873:
874: return thread;
875: }
876:
877: /* Cancel thread from scheduler. */
878: void
879: thread_cancel (struct thread *thread)
880: {
881: struct thread_list *list;
882:
883: 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);
888: list = &thread->master->read;
889: break;
890: case THREAD_WRITE:
891: assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
892: FD_CLR (thread->u.fd, &thread->master->writefd);
893: list = &thread->master->write;
894: break;
895: case THREAD_TIMER:
896: list = &thread->master->timer;
897: break;
898: case THREAD_EVENT:
899: list = &thread->master->event;
900: break;
901: case THREAD_READY:
902: list = &thread->master->ready;
903: break;
904: case THREAD_BACKGROUND:
905: list = &thread->master->background;
906: break;
907: default:
908: return;
909: break;
910: }
911: thread_list_delete (list, thread);
912: thread->type = THREAD_UNUSED;
913: thread_add_unuse (thread->master, thread);
914: }
915:
916: /* Delete all events which has argument value arg. */
917: unsigned int
918: thread_cancel_event (struct thread_master *m, void *arg)
919: {
920: unsigned int ret = 0;
921: 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)
932: {
933: ret++;
934: thread_list_delete (&m->event, t);
935: t->type = THREAD_UNUSED;
936: thread_add_unuse (m, t);
937: }
938: }
1.1.1.3 ! misho 939:
! 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: }
1.1 misho 957: return ret;
958: }
959:
960: static struct timeval *
961: thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
962: {
963: if (!thread_empty (tlist))
964: {
965: *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
966: return timer_val;
967: }
968: return NULL;
969: }
970:
971: static struct thread *
972: thread_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:
981: static int
982: thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
983: {
984: struct thread *thread;
985: struct thread *next;
986: int ready = 0;
987:
988: assert (list);
989:
990: for (thread = list->head; thread; thread = next)
991: {
992: next = thread->next;
993:
994: if (FD_ISSET (THREAD_FD (thread), fdset))
995: {
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: }
1003: }
1004: return ready;
1005: }
1006:
1007: /* Add all timers that have popped to the ready list. */
1008: static unsigned int
1009: thread_timer_process (struct thread_list *list, struct timeval *timenow)
1010: {
1011: struct thread *thread;
1.1.1.2 misho 1012: struct thread *next;
1.1 misho 1013: unsigned int ready = 0;
1014:
1.1.1.2 misho 1015: for (thread = list->head; thread; thread = next)
1.1 misho 1016: {
1.1.1.2 misho 1017: next = thread->next;
1.1 misho 1018: 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: }
1025: return ready;
1026: }
1027:
1028: /* process a list en masse, e.g. for event thread lists */
1029: static unsigned int
1030: thread_process (struct thread_list *list)
1031: {
1032: struct thread *thread;
1.1.1.2 misho 1033: struct thread *next;
1.1 misho 1034: unsigned int ready = 0;
1035:
1.1.1.2 misho 1036: for (thread = list->head; thread; thread = next)
1.1 misho 1037: {
1.1.1.2 misho 1038: next = thread->next;
1.1 misho 1039: 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:
1048: /* Fetch next ready thread. */
1049: struct thread *
1050: thread_fetch (struct thread_master *m, struct thread *fetch)
1051: {
1052: struct thread *thread;
1053: fd_set readfd;
1054: fd_set writefd;
1055: fd_set exceptfd;
1056: struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
1057: struct timeval timer_val_bg;
1058: struct timeval *timer_wait = &timer_val;
1059: struct timeval *timer_wait_bg;
1060:
1061: while (1)
1062: {
1063: int num = 0;
1.1.1.3 ! misho 1064: #if defined HAVE_SNMP && defined SNMP_AGENTX
! 1065: struct timeval snmp_timer_wait;
! 1066: int snmpblock = 0;
! 1067: int fdsetsize;
! 1068: #endif
1.1 misho 1069:
1070: /* Signals pre-empt everything */
1071: quagga_sigevent_process ();
1072:
1073: /* Drain the ready queue of already scheduled jobs, before scheduling
1074: * more.
1075: */
1076: if ((thread = thread_trim_head (&m->ready)) != NULL)
1077: return thread_run (m, thread, fetch);
1078:
1079: /* 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:
1087: /* Structure copy. */
1088: readfd = m->readfd;
1089: writefd = m->writefd;
1090: exceptfd = m->exceptfd;
1091:
1092: /* Calculate select wait timer if nothing else to do */
1093: 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: }
1103:
1.1.1.3 ! misho 1104: #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
1.1 misho 1124: num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
1125:
1126: /* Signals should get quick treatment */
1127: if (num < 0)
1128: {
1129: if (errno == EINTR)
1130: continue; /* signal received - process it */
1131: zlog_warn ("select() error: %s", safe_strerror (errno));
1132: return NULL;
1133: }
1134:
1.1.1.3 ! misho 1135: #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:
1.1 misho 1149: /* 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. */
1152: quagga_get_relative (NULL);
1153: thread_timer_process (&m->timer, &relative_time);
1154:
1155: /* Got IO, process it */
1156: if (num > 0)
1157: {
1158: /* Normal priority read thead. */
1159: thread_process_fd (&m->read, &readfd, &m->readfd);
1160: /* Write thead. */
1161: thread_process_fd (&m->write, &writefd, &m->writefd);
1162: }
1163:
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:
1173: /* Background timer/events, lowest priority */
1174: thread_timer_process (&m->background, &relative_time);
1175:
1176: if ((thread = thread_trim_head (&m->ready)) != NULL)
1177: return thread_run (m, thread, fetch);
1178: }
1179: }
1180:
1181: unsigned long
1182: thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
1183: {
1184: #ifdef HAVE_RUSAGE
1185: /* This is 'user + sys' time. */
1186: *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1187: timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
1188: #else
1189: *cputime = 0;
1190: #endif /* HAVE_RUSAGE */
1191: return timeval_elapsed (now->real, start->real);
1192: }
1193:
1194: /* 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. */
1203: int
1204: thread_should_yield (struct thread *thread)
1205: {
1206: quagga_get_relative (NULL);
1.1.1.3 ! misho 1207: return (timeval_elapsed(relative_time, thread->real) >
1.1 misho 1208: THREAD_YIELD_TIME_SLOT);
1209: }
1210:
1211: void
1212: thread_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:
1229: /* We check thread consumed time. If the system has getrusage, we'll
1230: use that to get in-depth stats on the performance of the thread in addition
1231: to wall clock time stats from gettimeofday. */
1232: void
1233: thread_call (struct thread *thread)
1234: {
1235: unsigned long realtime, cputime;
1.1.1.3 ! misho 1236: RUSAGE_T before, after;
1.1 misho 1237:
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;
1.1.1.3 ! misho 1249: strcpy(tmp.funcname, thread->funcname);
1.1 misho 1250:
1251: thread->hist = hash_get (cpu_record, &tmp,
1252: (void * (*) (void *))cpu_record_hash_alloc);
1253: }
1254:
1.1.1.3 ! misho 1255: GETRUSAGE (&before);
! 1256: thread->real = before.real;
1.1 misho 1257:
1258: (*thread->func) (thread);
1259:
1.1.1.3 ! misho 1260: GETRUSAGE (&after);
1.1 misho 1261:
1.1.1.3 ! misho 1262: realtime = thread_consumed_time (&after, &before, &cputime);
1.1 misho 1263: thread->hist->real.total += realtime;
1264: if (thread->hist->real.max < realtime)
1265: thread->hist->real.max = realtime;
1266: #ifdef HAVE_RUSAGE
1267: thread->hist->cpu.total += cputime;
1268: if (thread->hist->cpu.max < cputime)
1269: thread->hist->cpu.max = cputime;
1270: #endif
1271:
1272: ++(thread->hist->total_calls);
1273: thread->hist->types |= (1 << thread->add_type);
1274:
1275: #ifdef CONSUMED_TIME_CHECK
1276: if (realtime > CONSUMED_TIME_CHECK)
1277: {
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: */
1283: zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1284: thread->funcname,
1285: (unsigned long) thread->func,
1286: realtime/1000, cputime/1000);
1287: }
1288: #endif /* CONSUMED_TIME_CHECK */
1289: }
1290:
1291: /* Execute thread */
1292: struct thread *
1293: funcname_thread_execute (struct thread_master *m,
1294: int (*func)(struct thread *),
1295: void *arg,
1296: int val,
1297: const char* funcname)
1298: {
1299: struct thread dummy;
1300:
1301: memset (&dummy, 0, sizeof (struct thread));
1302:
1303: dummy.type = THREAD_EVENT;
1304: dummy.add_type = THREAD_EXECUTE;
1305: dummy.master = NULL;
1306: dummy.func = func;
1307: dummy.arg = arg;
1308: dummy.u.val = val;
1.1.1.3 ! misho 1309: strip_funcname (dummy.funcname, funcname);
1.1 misho 1310: thread_call (&dummy);
1311:
1312: return NULL;
1313: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>