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