Annotation of embedaddon/quagga/lib/thread.c, revision 1.1.1.1
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"
32:
33: /* Recent absolute time of day */
34: struct timeval recent_time;
35: static struct timeval last_recent_time;
36: /* Relative time, since startup */
37: static struct timeval relative_time;
38: static struct timeval relative_time_base;
39: /* init flag */
40: static unsigned short timers_inited;
41:
42: static struct hash *cpu_record = NULL;
43:
44: /* Struct timeval's tv_usec one second value. */
45: #define TIMER_SECOND_MICRO 1000000L
46:
47: /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
48: And change negative values to 0. */
49: static struct timeval
50: timeval_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)
65: /* Change negative timeouts to 0. */
66: a.tv_sec = a.tv_usec = 0;
67:
68: return a;
69: }
70:
71: static struct timeval
72: timeval_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:
82: static long
83: timeval_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:
89: static unsigned long
90: timeval_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:
96: #ifndef HAVE_CLOCK_MONOTONIC
97: static void
98: quagga_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 */
118: static int
119: quagga_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:
141: static int
142: quagga_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: */
169: static void
170: quagga_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: */
181: int
182: quagga_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: */
202: time_t
203: quagga_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 */
213: struct timeval
214: recent_relative_time (void)
215: {
216: return relative_time;
217: }
218:
219: static unsigned int
220: cpu_record_hash_key (struct cpu_thread_history *a)
221: {
222: return (uintptr_t) a->func;
223: }
224:
225: static int
226: cpu_record_hash_cmp (const struct cpu_thread_history *a,
227: const struct cpu_thread_history *b)
228: {
229: return a->func == b->func;
230: }
231:
232: static void *
233: cpu_record_hash_alloc (struct cpu_thread_history *a)
234: {
235: struct cpu_thread_history *new;
236: new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
237: new->func = a->func;
238: new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);
239: return new;
240: }
241:
242: static void
243: cpu_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:
251: static inline void
252: vty_out_cpu_thread_history(struct vty* vty,
253: struct cpu_thread_history *a)
254: {
255: #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",
266: 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':' ',
271: a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
272: a->funcname, VTY_NEWLINE);
273: }
274:
275: static void
276: cpu_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];
281: thread_type *filter = args[2];
282: struct cpu_thread_history *a = bucket->data;
283:
284: a = bucket->data;
285: if ( !(a->types & *filter) )
286: return;
287: vty_out_cpu_thread_history(vty,a);
288: totals->total_calls += a->total_calls;
289: 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
297: }
298:
299: static void
300: cpu_record_print(struct vty *vty, thread_type filter)
301: {
302: struct cpu_thread_history tmp;
303: void *args[3] = {&tmp, vty, &filter};
304:
305: memset(&tmp, 0, sizeof tmp);
306: tmp.funcname = (char *)"TOTAL";
307: tmp.types = filter;
308:
309: #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);
318: 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:
326: DEFUN(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"
332: "Display filter (rwtexb)\n")
333: {
334: int i = 0;
335: thread_type filter = (thread_type) -1U;
336:
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;
364: case 'b':
365: case 'B':
366: filter |= (1 << THREAD_BACKGROUND);
367: break;
368: default:
369: break;
370: }
371: ++i;
372: }
373: if (filter == 0)
374: {
375: vty_out(vty, "Invalid filter \"%s\" specified,"
376: " must contain at least one of 'RWTEXB'%s",
377: argv[0], VTY_NEWLINE);
378: return CMD_WARNING;
379: }
380: }
381:
382: cpu_record_print(vty, filter);
383: return CMD_SUCCESS;
384: }
385:
386: static void
387: cpu_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:
400: static void
401: cpu_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:
409: DEFUN(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: }
468:
469: /* List allocation and head/tail print out. */
470: static void
471: thread_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. */
478: static void __attribute__ ((unused))
479: thread_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);
492: printf ("bgndlist : ");
493: thread_list_debug (&m->background);
494: printf ("total alloc: [%ld]\n", m->alloc);
495: printf ("-----------\n");
496: }
497:
498: /* Allocate new thread master. */
499: struct thread_master *
500: thread_master_create ()
501: {
502: if (cpu_record == NULL)
503: cpu_record
504: = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
505: (int (*) (const void *, const void *))cpu_record_hash_cmp);
506:
507: return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
508: sizeof (struct thread_master));
509: }
510:
511: /* Add a new thread to the list. */
512: static void
513: thread_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. */
526: static void
527: thread_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. */
542: static struct thread *
543: thread_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. */
559: static void
560: thread_add_unuse (struct thread_master *m, struct thread *thread)
561: {
562: assert (m != NULL && thread != NULL);
563: assert (thread->next == NULL);
564: assert (thread->prev == NULL);
565: assert (thread->type == THREAD_UNUSED);
566: thread_list_add (&m->unuse, thread);
567: /* XXX: Should we deallocate funcname here? */
568: }
569:
570: /* Free all unused thread. */
571: static void
572: thread_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;
580: if (t->funcname)
581: XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);
582: XFREE (MTYPE_THREAD, t);
583: list->count--;
584: m->alloc--;
585: }
586: }
587:
588: /* Stop thread scheduler. */
589: void
590: thread_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);
598: thread_list_free (m, &m->background);
599:
600: XFREE (MTYPE_THREAD_MASTER, m);
601:
602: if (cpu_record)
603: {
604: hash_clean (cpu_record, cpu_record_hash_free);
605: hash_free (cpu_record);
606: cpu_record = NULL;
607: }
608: }
609:
610: /* Thread list is empty or not. */
611: static inline int
612: thread_empty (struct thread_list *list)
613: {
614: return list->head ? 0 : 1;
615: }
616:
617: /* Delete top of the list and return it. */
618: static struct thread *
619: thread_trim_head (struct thread_list *list)
620: {
621: if (!thread_empty (list))
622: return thread_list_delete (list, list->head);
623: return NULL;
624: }
625:
626: /* Return remain time in second. */
627: unsigned long
628: thread_timer_remain_second (struct thread *thread)
629: {
630: 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;
634: else
635: return 0;
636: }
637:
638: /* Trim blankspace and "()"s */
639: static char *
640: strip_funcname (const char *funcname)
641: {
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';
659: ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b);
660: *e = tmp;
661:
662: return ret;
663: }
664:
665: /* Get new thread. */
666: static struct thread *
667: thread_get (struct thread_master *m, u_char type,
668: int (*func) (struct thread *), void *arg, const char* funcname)
669: {
670: struct thread *thread;
671:
672: if (!thread_empty (&m->unuse))
673: {
674: thread = thread_trim_head (&m->unuse);
675: if (thread->funcname)
676: XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);
677: }
678: else
679: {
680: thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
681: m->alloc++;
682: }
683: thread->type = type;
684: thread->add_type = type;
685: thread->master = m;
686: thread->func = func;
687: thread->arg = arg;
688:
689: thread->funcname = strip_funcname(funcname);
690:
691: return thread;
692: }
693:
694: /* Add new read thread. */
695: struct thread *
696: funcname_thread_add_read (struct thread_master *m,
697: int (*func) (struct thread *), void *arg, int fd, const char* funcname)
698: {
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:
709: thread = thread_get (m, THREAD_READ, func, arg, funcname);
710: 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. */
718: struct thread *
719: funcname_thread_add_write (struct thread_master *m,
720: int (*func) (struct thread *), void *arg, int fd, const char* funcname)
721: {
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:
732: thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
733: FD_SET (fd, &m->writefd);
734: thread->u.fd = fd;
735: thread_list_add (&m->write, thread);
736:
737: return thread;
738: }
739:
740: static struct thread *
741: funcname_thread_add_timer_timeval (struct thread_master *m,
742: int (*func) (struct thread *),
743: int type,
744: void *arg,
745: struct timeval *time_relative,
746: const char* funcname)
747: {
748: struct thread *thread;
749: struct thread_list *list;
750: struct timeval alarm_time;
751: struct thread *tt;
752:
753: assert (m != NULL);
754:
755: assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
756: assert (time_relative);
757:
758: list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
759: thread = thread_get (m, type, func, arg, funcname);
760:
761: /* Do we need jitter here? */
762: quagga_get_relative (NULL);
763: 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;
765: thread->u.sands = timeval_adjust(alarm_time);
766:
767: /* Sort by timeval. */
768: for (tt = list->head; tt; tt = tt->next)
769: if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
770: break;
771:
772: if (tt)
773: thread_list_add_before (list, tt, thread);
774: else
775: thread_list_add (list, thread);
776:
777: return thread;
778: }
779:
780:
781: /* Add timer event thread. */
782: struct thread *
783: funcname_thread_add_timer (struct thread_master *m,
784: int (*func) (struct thread *),
785: void *arg, long timer, const char* funcname)
786: {
787: struct timeval trel;
788:
789: assert (m != NULL);
790:
791: trel.tv_sec = timer;
792: trel.tv_usec = 0;
793:
794: return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
795: &trel, funcname);
796: }
797:
798: /* Add timer event thread with "millisecond" resolution */
799: struct thread *
800: funcname_thread_add_timer_msec (struct thread_master *m,
801: int (*func) (struct thread *),
802: void *arg, long timer, const char* funcname)
803: {
804: struct timeval trel;
805:
806: assert (m != NULL);
807:
808: trel.tv_sec = timer / 1000;
809: trel.tv_usec = 1000*(timer % 1000);
810:
811: 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 */
816: struct thread *
817: funcname_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);
839: }
840:
841: /* Add simple event thread. */
842: struct thread *
843: funcname_thread_add_event (struct thread_master *m,
844: int (*func) (struct thread *), void *arg, int val, const char* funcname)
845: {
846: struct thread *thread;
847:
848: assert (m != NULL);
849:
850: thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
851: thread->u.val = val;
852: thread_list_add (&m->event, thread);
853:
854: return thread;
855: }
856:
857: /* Cancel thread from scheduler. */
858: void
859: thread_cancel (struct thread *thread)
860: {
861: struct thread_list *list;
862:
863: 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);
868: list = &thread->master->read;
869: break;
870: case THREAD_WRITE:
871: assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
872: FD_CLR (thread->u.fd, &thread->master->writefd);
873: list = &thread->master->write;
874: break;
875: case THREAD_TIMER:
876: list = &thread->master->timer;
877: break;
878: case THREAD_EVENT:
879: list = &thread->master->event;
880: break;
881: case THREAD_READY:
882: list = &thread->master->ready;
883: break;
884: case THREAD_BACKGROUND:
885: list = &thread->master->background;
886: break;
887: default:
888: return;
889: break;
890: }
891: thread_list_delete (list, thread);
892: thread->type = THREAD_UNUSED;
893: thread_add_unuse (thread->master, thread);
894: }
895:
896: /* Delete all events which has argument value arg. */
897: unsigned int
898: thread_cancel_event (struct thread_master *m, void *arg)
899: {
900: unsigned int ret = 0;
901: 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)
912: {
913: ret++;
914: thread_list_delete (&m->event, t);
915: t->type = THREAD_UNUSED;
916: thread_add_unuse (m, t);
917: }
918: }
919: return ret;
920: }
921:
922: static struct timeval *
923: thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
924: {
925: if (!thread_empty (tlist))
926: {
927: *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
928: return timer_val;
929: }
930: return NULL;
931: }
932:
933: static struct thread *
934: thread_run (struct thread_master *m, struct thread *thread,
935: struct thread *fetch)
936: {
937: *fetch = *thread;
938: thread->type = THREAD_UNUSED;
939: thread->funcname = NULL; /* thread_call will free fetch's copied pointer */
940: thread_add_unuse (m, thread);
941: return fetch;
942: }
943:
944: static int
945: thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
946: {
947: struct thread *thread;
948: struct thread *next;
949: int ready = 0;
950:
951: assert (list);
952:
953: for (thread = list->head; thread; thread = next)
954: {
955: next = thread->next;
956:
957: if (FD_ISSET (THREAD_FD (thread), fdset))
958: {
959: assert (FD_ISSET (THREAD_FD (thread), mfdset));
960: FD_CLR(THREAD_FD (thread), mfdset);
961: thread_list_delete (list, thread);
962: thread_list_add (&thread->master->ready, thread);
963: thread->type = THREAD_READY;
964: ready++;
965: }
966: }
967: return ready;
968: }
969:
970: /* Add all timers that have popped to the ready list. */
971: static unsigned int
972: thread_timer_process (struct thread_list *list, struct timeval *timenow)
973: {
974: struct thread *thread;
975: unsigned int ready = 0;
976:
977: for (thread = list->head; thread; thread = thread->next)
978: {
979: if (timeval_cmp (*timenow, thread->u.sands) < 0)
980: return ready;
981: thread_list_delete (list, thread);
982: thread->type = THREAD_READY;
983: thread_list_add (&thread->master->ready, thread);
984: ready++;
985: }
986: return ready;
987: }
988:
989: /* process a list en masse, e.g. for event thread lists */
990: static unsigned int
991: thread_process (struct thread_list *list)
992: {
993: struct thread *thread;
994: unsigned int ready = 0;
995:
996: for (thread = list->head; thread; thread = thread->next)
997: {
998: thread_list_delete (list, thread);
999: thread->type = THREAD_READY;
1000: thread_list_add (&thread->master->ready, thread);
1001: ready++;
1002: }
1003: return ready;
1004: }
1005:
1006:
1007: /* Fetch next ready thread. */
1008: struct thread *
1009: thread_fetch (struct thread_master *m, struct thread *fetch)
1010: {
1011: struct thread *thread;
1012: fd_set readfd;
1013: fd_set writefd;
1014: fd_set exceptfd;
1015: struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
1016: struct timeval timer_val_bg;
1017: struct timeval *timer_wait = &timer_val;
1018: struct timeval *timer_wait_bg;
1019:
1020: while (1)
1021: {
1022: int num = 0;
1023:
1024: /* Signals pre-empt everything */
1025: quagga_sigevent_process ();
1026:
1027: /* Drain the ready queue of already scheduled jobs, before scheduling
1028: * more.
1029: */
1030: if ((thread = thread_trim_head (&m->ready)) != NULL)
1031: return thread_run (m, thread, fetch);
1032:
1033: /* To be fair to all kinds of threads, and avoid starvation, we
1034: * need to be careful to consider all thread types for scheduling
1035: * in each quanta. I.e. we should not return early from here on.
1036: */
1037:
1038: /* Normal event are the next highest priority. */
1039: thread_process (&m->event);
1040:
1041: /* Structure copy. */
1042: readfd = m->readfd;
1043: writefd = m->writefd;
1044: exceptfd = m->exceptfd;
1045:
1046: /* Calculate select wait timer if nothing else to do */
1047: if (m->ready.count == 0)
1048: {
1049: quagga_get_relative (NULL);
1050: timer_wait = thread_timer_wait (&m->timer, &timer_val);
1051: timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
1052:
1053: if (timer_wait_bg &&
1054: (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1055: timer_wait = timer_wait_bg;
1056: }
1057:
1058: num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
1059:
1060: /* Signals should get quick treatment */
1061: if (num < 0)
1062: {
1063: if (errno == EINTR)
1064: continue; /* signal received - process it */
1065: zlog_warn ("select() error: %s", safe_strerror (errno));
1066: return NULL;
1067: }
1068:
1069: /* Check foreground timers. Historically, they have had higher
1070: priority than I/O threads, so let's push them onto the ready
1071: list in front of the I/O threads. */
1072: quagga_get_relative (NULL);
1073: thread_timer_process (&m->timer, &relative_time);
1074:
1075: /* Got IO, process it */
1076: if (num > 0)
1077: {
1078: /* Normal priority read thead. */
1079: thread_process_fd (&m->read, &readfd, &m->readfd);
1080: /* Write thead. */
1081: thread_process_fd (&m->write, &writefd, &m->writefd);
1082: }
1083:
1084: #if 0
1085: /* If any threads were made ready above (I/O or foreground timer),
1086: perhaps we should avoid adding background timers to the ready
1087: list at this time. If this is code is uncommented, then background
1088: timer threads will not run unless there is nothing else to do. */
1089: if ((thread = thread_trim_head (&m->ready)) != NULL)
1090: return thread_run (m, thread, fetch);
1091: #endif
1092:
1093: /* Background timer/events, lowest priority */
1094: thread_timer_process (&m->background, &relative_time);
1095:
1096: if ((thread = thread_trim_head (&m->ready)) != NULL)
1097: return thread_run (m, thread, fetch);
1098: }
1099: }
1100:
1101: unsigned long
1102: thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
1103: {
1104: #ifdef HAVE_RUSAGE
1105: /* This is 'user + sys' time. */
1106: *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1107: timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
1108: #else
1109: *cputime = 0;
1110: #endif /* HAVE_RUSAGE */
1111: return timeval_elapsed (now->real, start->real);
1112: }
1113:
1114: /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1115: Note: we are using real (wall clock) time for this calculation.
1116: It could be argued that CPU time may make more sense in certain
1117: contexts. The things to consider are whether the thread may have
1118: blocked (in which case wall time increases, but CPU time does not),
1119: or whether the system is heavily loaded with other processes competing
1120: for CPU time. On balance, wall clock time seems to make sense.
1121: Plus it has the added benefit that gettimeofday should be faster
1122: than calling getrusage. */
1123: int
1124: thread_should_yield (struct thread *thread)
1125: {
1126: quagga_get_relative (NULL);
1127: return (timeval_elapsed(relative_time, thread->ru.real) >
1128: THREAD_YIELD_TIME_SLOT);
1129: }
1130:
1131: void
1132: thread_getrusage (RUSAGE_T *r)
1133: {
1134: quagga_get_relative (NULL);
1135: #ifdef HAVE_RUSAGE
1136: getrusage(RUSAGE_SELF, &(r->cpu));
1137: #endif
1138: r->real = relative_time;
1139:
1140: #ifdef HAVE_CLOCK_MONOTONIC
1141: /* quagga_get_relative() only updates recent_time if gettimeofday
1142: * based, not when using CLOCK_MONOTONIC. As we export recent_time
1143: * and guarantee to update it before threads are run...
1144: */
1145: quagga_gettimeofday(&recent_time);
1146: #endif /* HAVE_CLOCK_MONOTONIC */
1147: }
1148:
1149: /* We check thread consumed time. If the system has getrusage, we'll
1150: use that to get in-depth stats on the performance of the thread in addition
1151: to wall clock time stats from gettimeofday. */
1152: void
1153: thread_call (struct thread *thread)
1154: {
1155: unsigned long realtime, cputime;
1156: RUSAGE_T ru;
1157:
1158: /* Cache a pointer to the relevant cpu history thread, if the thread
1159: * does not have it yet.
1160: *
1161: * Callers submitting 'dummy threads' hence must take care that
1162: * thread->cpu is NULL
1163: */
1164: if (!thread->hist)
1165: {
1166: struct cpu_thread_history tmp;
1167:
1168: tmp.func = thread->func;
1169: tmp.funcname = thread->funcname;
1170:
1171: thread->hist = hash_get (cpu_record, &tmp,
1172: (void * (*) (void *))cpu_record_hash_alloc);
1173: }
1174:
1175: GETRUSAGE (&thread->ru);
1176:
1177: (*thread->func) (thread);
1178:
1179: GETRUSAGE (&ru);
1180:
1181: realtime = thread_consumed_time (&ru, &thread->ru, &cputime);
1182: thread->hist->real.total += realtime;
1183: if (thread->hist->real.max < realtime)
1184: thread->hist->real.max = realtime;
1185: #ifdef HAVE_RUSAGE
1186: thread->hist->cpu.total += cputime;
1187: if (thread->hist->cpu.max < cputime)
1188: thread->hist->cpu.max = cputime;
1189: #endif
1190:
1191: ++(thread->hist->total_calls);
1192: thread->hist->types |= (1 << thread->add_type);
1193:
1194: #ifdef CONSUMED_TIME_CHECK
1195: if (realtime > CONSUMED_TIME_CHECK)
1196: {
1197: /*
1198: * We have a CPU Hog on our hands.
1199: * Whinge about it now, so we're aware this is yet another task
1200: * to fix.
1201: */
1202: zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1203: thread->funcname,
1204: (unsigned long) thread->func,
1205: realtime/1000, cputime/1000);
1206: }
1207: #endif /* CONSUMED_TIME_CHECK */
1208:
1209: XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname);
1210: }
1211:
1212: /* Execute thread */
1213: struct thread *
1214: funcname_thread_execute (struct thread_master *m,
1215: int (*func)(struct thread *),
1216: void *arg,
1217: int val,
1218: const char* funcname)
1219: {
1220: struct thread dummy;
1221:
1222: memset (&dummy, 0, sizeof (struct thread));
1223:
1224: dummy.type = THREAD_EVENT;
1225: dummy.add_type = THREAD_EXECUTE;
1226: dummy.master = NULL;
1227: dummy.func = func;
1228: dummy.arg = arg;
1229: dummy.u.val = val;
1230: dummy.funcname = strip_funcname (funcname);
1231: thread_call (&dummy);
1232:
1233: XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);
1234:
1235: return NULL;
1236: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>