1 /* Thread management routine
2 * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
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
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.
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
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>
40 extern int agentx_enabled
;
43 #if defined(__APPLE__)
44 #include <mach/mach.h>
45 #include <mach/mach_time.h>
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
;
56 static unsigned short timers_inited
;
58 static struct hash
*cpu_record
= NULL
;
60 /* Struct timeval's tv_usec one second value. */
61 #define TIMER_SECOND_MICRO 1000000L
63 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
64 And change negative values to 0. */
66 timeval_adjust (struct timeval a
)
68 while (a
.tv_usec
>= TIMER_SECOND_MICRO
)
70 a
.tv_usec
-= TIMER_SECOND_MICRO
;
76 a
.tv_usec
+= TIMER_SECOND_MICRO
;
81 /* Change negative timeouts to 0. */
82 a
.tv_sec
= a
.tv_usec
= 0;
88 timeval_subtract (struct timeval a
, struct timeval b
)
92 ret
.tv_usec
= a
.tv_usec
- b
.tv_usec
;
93 ret
.tv_sec
= a
.tv_sec
- b
.tv_sec
;
95 return timeval_adjust (ret
);
99 timeval_cmp (struct timeval a
, struct timeval b
)
101 return (a
.tv_sec
== b
.tv_sec
102 ? a
.tv_usec
- b
.tv_usec
: a
.tv_sec
- b
.tv_sec
);
106 timeval_elapsed (struct timeval a
, struct timeval b
)
108 return (((a
.tv_sec
- b
.tv_sec
) * TIMER_SECOND_MICRO
)
109 + (a
.tv_usec
- b
.tv_usec
));
112 #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
114 quagga_gettimeofday_relative_adjust (void)
117 if (timeval_cmp (recent_time
, last_recent_time
) < 0)
119 relative_time
.tv_sec
++;
120 relative_time
.tv_usec
= 0;
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
);
129 last_recent_time
= recent_time
;
131 #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
133 /* gettimeofday wrapper, to keep recent_time updated */
135 quagga_gettimeofday (struct timeval
*tv
)
141 if (!(ret
= gettimeofday (&recent_time
, NULL
)))
146 relative_time_base
= last_recent_time
= recent_time
;
149 /* avoid copy if user passed recent_time pointer.. */
150 if (tv
!= &recent_time
)
158 quagga_get_relative (struct timeval
*tv
)
162 #ifdef HAVE_CLOCK_MONOTONIC
165 if (!(ret
= clock_gettime (CLOCK_MONOTONIC
, &tp
)))
167 relative_time
.tv_sec
= tp
.tv_sec
;
168 relative_time
.tv_usec
= tp
.tv_nsec
/ 1000;
171 #elif defined(__APPLE__)
175 static mach_timebase_info_data_t timebase_info
;
177 ticks
= mach_absolute_time();
178 if (timebase_info
.denom
== 0)
179 mach_timebase_info(&timebase_info
);
181 useconds
= ticks
* timebase_info
.numer
/ timebase_info
.denom
/ 1000;
182 relative_time
.tv_sec
= useconds
/ 1000000;
183 relative_time
.tv_usec
= useconds
% 1000000;
187 #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
188 if (!(ret
= quagga_gettimeofday (&recent_time
)))
189 quagga_gettimeofday_relative_adjust();
190 #endif /* HAVE_CLOCK_MONOTONIC */
198 /* Get absolute time stamp, but in terms of the internal timer
199 * Could be wrong, but at least won't go back.
202 quagga_real_stabilised (struct timeval
*tv
)
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
);
210 /* Exported Quagga timestamp function.
211 * Modelled on POSIX clock_gettime.
214 quagga_gettime (enum quagga_clkid clkid
, struct timeval
*tv
)
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
);
231 /* time_t value in terms of stabilised absolute time.
232 * replacement for POSIX time()
235 quagga_time (time_t *t
)
238 quagga_real_stabilised (&tv
);
244 /* Public export of recent_relative_time by value */
246 recent_relative_time (void)
248 return relative_time
;
252 cpu_record_hash_key (struct cpu_thread_history
*a
)
254 return (uintptr_t) a
->func
;
258 cpu_record_hash_cmp (const struct cpu_thread_history
*a
,
259 const struct cpu_thread_history
*b
)
261 return a
->func
== b
->func
;
265 cpu_record_hash_alloc (struct cpu_thread_history
*a
)
267 struct cpu_thread_history
*new;
268 new = XCALLOC (MTYPE_THREAD_STATS
, sizeof (struct cpu_thread_history
));
270 strcpy(new->funcname
, a
->funcname
);
275 cpu_record_hash_free (void *a
)
277 struct cpu_thread_history
*hist
= a
;
279 XFREE (MTYPE_THREAD_STATS
, hist
);
283 vty_out_cpu_thread_history(struct vty
* vty
,
284 struct cpu_thread_history
*a
)
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
);
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
);
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
);
307 cpu_record_hash_print(struct hash_backet
*bucket
,
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
;
316 if ( !(a
->types
& *filter
) )
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
;
324 totals
->cpu
.total
+= a
->cpu
.total
;
325 if (totals
->cpu
.max
< a
->cpu
.max
)
326 totals
->cpu
.max
= a
->cpu
.max
;
331 cpu_record_print(struct vty
*vty
, thread_type filter
)
333 struct cpu_thread_history tmp
;
334 void *args
[3] = {&tmp
, vty
, &filter
};
336 memset(&tmp
, 0, sizeof tmp
);
337 strcpy(tmp
.funcname
, "TOTAL");
341 vty_out(vty
, "%21s %18s %18s%s",
342 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE
);
344 vty_out(vty
, "Runtime(ms) Invoked Avg uSec Max uSecs");
346 vty_out(vty
, " Avg uSec Max uSecs");
348 vty_out(vty
, " Type Thread%s", VTY_NEWLINE
);
349 hash_iterate(cpu_record
,
350 (void(*)(struct hash_backet
*,void*))cpu_record_hash_print
,
353 if (tmp
.total_calls
> 0)
354 vty_out_cpu_thread_history(vty
, &tmp
);
357 DEFUN(show_thread_cpu
,
359 "show thread cpu [FILTER]",
361 "Thread information\n"
363 "Display filter (rwtexb)\n")
366 thread_type filter
= (thread_type
) -1U;
371 while (argv
[0][i
] != '\0')
373 switch ( argv
[0][i
] )
377 filter
|= (1 << THREAD_READ
);
381 filter
|= (1 << THREAD_WRITE
);
385 filter
|= (1 << THREAD_TIMER
);
389 filter
|= (1 << THREAD_EVENT
);
393 filter
|= (1 << THREAD_EXECUTE
);
397 filter
|= (1 << THREAD_BACKGROUND
);
406 vty_out(vty
, "Invalid filter \"%s\" specified,"
407 " must contain at least one of 'RWTEXB'%s",
408 argv
[0], VTY_NEWLINE
);
413 cpu_record_print(vty
, filter
);
418 cpu_record_hash_clear (struct hash_backet
*bucket
,
421 thread_type
*filter
= args
;
422 struct cpu_thread_history
*a
= bucket
->data
;
425 if ( !(a
->types
& *filter
) )
428 hash_release (cpu_record
, bucket
->data
);
432 cpu_record_clear (thread_type filter
)
434 thread_type
*tmp
= &filter
;
435 hash_iterate (cpu_record
,
436 (void (*) (struct hash_backet
*,void*)) cpu_record_hash_clear
,
440 DEFUN(clear_thread_cpu
,
441 clear_thread_cpu_cmd
,
442 "clear thread cpu [FILTER]",
443 "Clear stored data\n"
444 "Thread information\n"
446 "Display filter (rwtexb)\n")
449 thread_type filter
= (thread_type
) -1U;
454 while (argv
[0][i
] != '\0')
456 switch ( argv
[0][i
] )
460 filter
|= (1 << THREAD_READ
);
464 filter
|= (1 << THREAD_WRITE
);
468 filter
|= (1 << THREAD_TIMER
);
472 filter
|= (1 << THREAD_EVENT
);
476 filter
|= (1 << THREAD_EXECUTE
);
480 filter
|= (1 << THREAD_BACKGROUND
);
489 vty_out(vty
, "Invalid filter \"%s\" specified,"
490 " must contain at least one of 'RWTEXB'%s",
491 argv
[0], VTY_NEWLINE
);
496 cpu_record_clear (filter
);
501 thread_timer_cmp(void *a
, void *b
)
503 struct thread
*thread_a
= a
;
504 struct thread
*thread_b
= b
;
506 long cmp
= timeval_cmp(thread_a
->u
.sands
, thread_b
->u
.sands
);
516 thread_timer_update(void *node
, int actual_position
)
518 struct thread
*thread
= node
;
520 thread
->index
= actual_position
;
523 /* Allocate new thread master. */
524 struct thread_master
*
525 thread_master_create ()
527 struct thread_master
*rv
;
529 if (cpu_record
== NULL
)
531 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key
,
532 (int (*) (const void *, const void *))cpu_record_hash_cmp
);
534 rv
= XCALLOC (MTYPE_THREAD_MASTER
, sizeof (struct thread_master
));
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
;
545 /* Add a new thread to the list. */
547 thread_list_add (struct thread_list
*list
, struct thread
*thread
)
550 thread
->prev
= list
->tail
;
552 list
->tail
->next
= thread
;
559 /* Delete a thread from the list. */
560 static struct thread
*
561 thread_list_delete (struct thread_list
*list
, struct thread
*thread
)
564 thread
->next
->prev
= thread
->prev
;
566 list
->tail
= thread
->prev
;
568 thread
->prev
->next
= thread
->next
;
570 list
->head
= thread
->next
;
571 thread
->next
= thread
->prev
= NULL
;
576 /* Move thread to unuse list. */
578 thread_add_unuse (struct thread_master
*m
, struct thread
*thread
)
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 /* XXX: Should we deallocate funcname here? */
588 /* Free all unused thread. */
590 thread_list_free (struct thread_master
*m
, struct thread_list
*list
)
595 for (t
= list
->head
; t
; t
= next
)
598 XFREE (MTYPE_THREAD
, t
);
605 thread_queue_free (struct thread_master
*m
, struct pqueue
*queue
)
609 for (i
= 0; i
< queue
->size
; i
++)
610 XFREE(MTYPE_THREAD
, queue
->array
[i
]);
612 m
->alloc
-= queue
->size
;
613 pqueue_delete(queue
);
616 /* Stop thread scheduler. */
618 thread_master_free (struct thread_master
*m
)
620 thread_list_free (m
, &m
->read
);
621 thread_list_free (m
, &m
->write
);
622 thread_queue_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_queue_free (m
, m
->background
);
628 XFREE (MTYPE_THREAD_MASTER
, m
);
632 hash_clean (cpu_record
, cpu_record_hash_free
);
633 hash_free (cpu_record
);
638 /* Thread list is empty or not. */
640 thread_empty (struct thread_list
*list
)
642 return list
->head
? 0 : 1;
645 /* Delete top of the list and return it. */
646 static struct thread
*
647 thread_trim_head (struct thread_list
*list
)
649 if (!thread_empty (list
))
650 return thread_list_delete (list
, list
->head
);
654 /* Return remain time in second. */
656 thread_timer_remain_second (struct thread
*thread
)
658 quagga_get_relative (NULL
);
660 if (thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
> 0)
661 return thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
;
666 /* Trim blankspace and "()"s */
668 strip_funcname (char *dest
, const char *funcname
)
670 char buff
[FUNCNAME_LEN
];
671 char tmp
, *e
, *b
= buff
;
673 strncpy(buff
, funcname
, sizeof(buff
));
674 buff
[ sizeof(buff
) -1] = '\0';
675 e
= buff
+strlen(buff
) -1;
677 /* Wont work for funcname == "Word (explanation)" */
679 while (*b
== ' ' || *b
== '(')
681 while (*e
== ' ' || *e
== ')')
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
)
696 struct thread
*thread
= thread_trim_head (&m
->unuse
);
700 thread
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
));
704 thread
->add_type
= type
;
710 strip_funcname (thread
->funcname
, funcname
);
715 /* Add new read thread. */
717 funcname_thread_add_read (struct thread_master
*m
,
718 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
720 struct thread
*thread
;
724 if (FD_ISSET (fd
, &m
->readfd
))
726 zlog (NULL
, LOG_WARNING
, "There is already read fd [%d]", fd
);
730 thread
= thread_get (m
, THREAD_READ
, func
, arg
, funcname
);
731 FD_SET (fd
, &m
->readfd
);
733 thread_list_add (&m
->read
, thread
);
738 /* Add new write thread. */
740 funcname_thread_add_write (struct thread_master
*m
,
741 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
743 struct thread
*thread
;
747 if (FD_ISSET (fd
, &m
->writefd
))
749 zlog (NULL
, LOG_WARNING
, "There is already write fd [%d]", fd
);
753 thread
= thread_get (m
, THREAD_WRITE
, func
, arg
, funcname
);
754 FD_SET (fd
, &m
->writefd
);
756 thread_list_add (&m
->write
, thread
);
761 static struct thread
*
762 funcname_thread_add_timer_timeval (struct thread_master
*m
,
763 int (*func
) (struct thread
*),
766 struct timeval
*time_relative
,
767 const char* funcname
)
769 struct thread
*thread
;
770 struct pqueue
*queue
;
771 struct timeval alarm_time
;
775 assert (type
== THREAD_TIMER
|| type
== THREAD_BACKGROUND
);
776 assert (time_relative
);
778 queue
= ((type
== THREAD_TIMER
) ? m
->timer
: m
->background
);
779 thread
= thread_get (m
, type
, func
, arg
, funcname
);
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
);
787 pqueue_enqueue(thread
, queue
);
792 /* Add timer event thread. */
794 funcname_thread_add_timer (struct thread_master
*m
,
795 int (*func
) (struct thread
*),
796 void *arg
, long timer
, const char* funcname
)
805 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
, arg
,
809 /* Add timer event thread with "millisecond" resolution */
811 funcname_thread_add_timer_msec (struct thread_master
*m
,
812 int (*func
) (struct thread
*),
813 void *arg
, long timer
, const char* funcname
)
819 trel
.tv_sec
= timer
/ 1000;
820 trel
.tv_usec
= 1000*(timer
% 1000);
822 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
823 arg
, &trel
, funcname
);
826 /* Add a background thread, with an optional millisec delay */
828 funcname_thread_add_background (struct thread_master
*m
,
829 int (*func
) (struct thread
*),
830 void *arg
, long delay
,
831 const char *funcname
)
839 trel
.tv_sec
= delay
/ 1000;
840 trel
.tv_usec
= 1000*(delay
% 1000);
848 return funcname_thread_add_timer_timeval (m
, func
, THREAD_BACKGROUND
,
849 arg
, &trel
, funcname
);
852 /* Add simple event thread. */
854 funcname_thread_add_event (struct thread_master
*m
,
855 int (*func
) (struct thread
*), void *arg
, int val
, const char* funcname
)
857 struct thread
*thread
;
861 thread
= thread_get (m
, THREAD_EVENT
, func
, arg
, funcname
);
863 thread_list_add (&m
->event
, thread
);
868 /* Cancel thread from scheduler. */
870 thread_cancel (struct thread
*thread
)
872 struct thread_list
*list
= NULL
;
873 struct pqueue
*queue
= NULL
;
875 switch (thread
->type
)
878 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->readfd
));
879 FD_CLR (thread
->u
.fd
, &thread
->master
->readfd
);
880 list
= &thread
->master
->read
;
883 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->writefd
));
884 FD_CLR (thread
->u
.fd
, &thread
->master
->writefd
);
885 list
= &thread
->master
->write
;
888 queue
= thread
->master
->timer
;
891 list
= &thread
->master
->event
;
894 list
= &thread
->master
->ready
;
896 case THREAD_BACKGROUND
:
897 queue
= thread
->master
->background
;
906 assert(thread
->index
>= 0);
907 assert(thread
== queue
->array
[thread
->index
]);
908 pqueue_remove_at(thread
->index
, queue
);
912 thread_list_delete (list
, thread
);
916 assert(!"Thread should be either in queue or list!");
919 thread
->type
= THREAD_UNUSED
;
920 thread_add_unuse (thread
->master
, thread
);
923 /* Delete all events which has argument value arg. */
925 thread_cancel_event (struct thread_master
*m
, void *arg
)
927 unsigned int ret
= 0;
928 struct thread
*thread
;
930 thread
= m
->event
.head
;
941 thread_list_delete (&m
->event
, t
);
942 t
->type
= THREAD_UNUSED
;
943 thread_add_unuse (m
, t
);
947 /* thread can be on the ready list too */
948 thread
= m
->ready
.head
;
959 thread_list_delete (&m
->ready
, t
);
960 t
->type
= THREAD_UNUSED
;
961 thread_add_unuse (m
, t
);
967 static struct timeval
*
968 thread_timer_wait (struct pqueue
*queue
, struct timeval
*timer_val
)
972 struct thread
*next_timer
= queue
->array
[0];
973 *timer_val
= timeval_subtract (next_timer
->u
.sands
, relative_time
);
979 static struct thread
*
980 thread_run (struct thread_master
*m
, struct thread
*thread
,
981 struct thread
*fetch
)
984 thread
->type
= THREAD_UNUSED
;
985 thread_add_unuse (m
, thread
);
990 thread_process_fd (struct thread_list
*list
, fd_set
*fdset
, fd_set
*mfdset
)
992 struct thread
*thread
;
998 for (thread
= list
->head
; thread
; thread
= next
)
1000 next
= thread
->next
;
1002 if (FD_ISSET (THREAD_FD (thread
), fdset
))
1004 assert (FD_ISSET (THREAD_FD (thread
), mfdset
));
1005 FD_CLR(THREAD_FD (thread
), mfdset
);
1006 thread_list_delete (list
, thread
);
1007 thread_list_add (&thread
->master
->ready
, thread
);
1008 thread
->type
= THREAD_READY
;
1015 /* Add all timers that have popped to the ready list. */
1017 thread_timer_process (struct pqueue
*queue
, struct timeval
*timenow
)
1019 struct thread
*thread
;
1020 unsigned int ready
= 0;
1024 thread
= queue
->array
[0];
1025 if (timeval_cmp (*timenow
, thread
->u
.sands
) < 0)
1027 pqueue_dequeue(queue
);
1028 thread
->type
= THREAD_READY
;
1029 thread_list_add (&thread
->master
->ready
, thread
);
1035 /* process a list en masse, e.g. for event thread lists */
1037 thread_process (struct thread_list
*list
)
1039 struct thread
*thread
;
1040 struct thread
*next
;
1041 unsigned int ready
= 0;
1043 for (thread
= list
->head
; thread
; thread
= next
)
1045 next
= thread
->next
;
1046 thread_list_delete (list
, thread
);
1047 thread
->type
= THREAD_READY
;
1048 thread_list_add (&thread
->master
->ready
, thread
);
1055 /* Fetch next ready thread. */
1057 thread_fetch (struct thread_master
*m
, struct thread
*fetch
)
1059 struct thread
*thread
;
1063 struct timeval timer_val
= { .tv_sec
= 0, .tv_usec
= 0 };
1064 struct timeval timer_val_bg
;
1065 struct timeval
*timer_wait
= &timer_val
;
1066 struct timeval
*timer_wait_bg
;
1071 #if defined HAVE_SNMP && defined SNMP_AGENTX
1072 struct timeval snmp_timer_wait
;
1077 /* Signals pre-empt everything */
1078 quagga_sigevent_process ();
1080 /* Drain the ready queue of already scheduled jobs, before scheduling
1083 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1084 return thread_run (m
, thread
, fetch
);
1086 /* To be fair to all kinds of threads, and avoid starvation, we
1087 * need to be careful to consider all thread types for scheduling
1088 * in each quanta. I.e. we should not return early from here on.
1091 /* Normal event are the next highest priority. */
1092 thread_process (&m
->event
);
1094 /* Structure copy. */
1096 writefd
= m
->writefd
;
1097 exceptfd
= m
->exceptfd
;
1099 /* Calculate select wait timer if nothing else to do */
1100 if (m
->ready
.count
== 0)
1102 quagga_get_relative (NULL
);
1103 timer_wait
= thread_timer_wait (m
->timer
, &timer_val
);
1104 timer_wait_bg
= thread_timer_wait (m
->background
, &timer_val_bg
);
1106 if (timer_wait_bg
&&
1107 (!timer_wait
|| (timeval_cmp (*timer_wait
, *timer_wait_bg
) > 0)))
1108 timer_wait
= timer_wait_bg
;
1111 #if defined HAVE_SNMP && defined SNMP_AGENTX
1112 /* When SNMP is enabled, we may have to select() on additional
1113 FD. snmp_select_info() will add them to `readfd'. The trick
1114 with this function is its last argument. We need to set it to
1115 0 if timer_wait is not NULL and we need to use the provided
1116 new timer only if it is still set to 0. */
1119 fdsetsize
= FD_SETSIZE
;
1124 memcpy(&snmp_timer_wait
, timer_wait
, sizeof(struct timeval
));
1126 snmp_select_info(&fdsetsize
, &readfd
, &snmp_timer_wait
, &snmpblock
);
1128 timer_wait
= &snmp_timer_wait
;
1131 num
= select (FD_SETSIZE
, &readfd
, &writefd
, &exceptfd
, timer_wait
);
1133 /* Signals should get quick treatment */
1137 continue; /* signal received - process it */
1138 zlog_warn ("select() error: %s", safe_strerror (errno
));
1142 #if defined HAVE_SNMP && defined SNMP_AGENTX
1152 netsnmp_check_outstanding_agent_requests();
1156 /* Check foreground timers. Historically, they have had higher
1157 priority than I/O threads, so let's push them onto the ready
1158 list in front of the I/O threads. */
1159 quagga_get_relative (NULL
);
1160 thread_timer_process (m
->timer
, &relative_time
);
1162 /* Got IO, process it */
1165 /* Normal priority read thead. */
1166 thread_process_fd (&m
->read
, &readfd
, &m
->readfd
);
1168 thread_process_fd (&m
->write
, &writefd
, &m
->writefd
);
1172 /* If any threads were made ready above (I/O or foreground timer),
1173 perhaps we should avoid adding background timers to the ready
1174 list at this time. If this is code is uncommented, then background
1175 timer threads will not run unless there is nothing else to do. */
1176 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1177 return thread_run (m
, thread
, fetch
);
1180 /* Background timer/events, lowest priority */
1181 thread_timer_process (m
->background
, &relative_time
);
1183 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1184 return thread_run (m
, thread
, fetch
);
1189 thread_consumed_time (RUSAGE_T
*now
, RUSAGE_T
*start
, unsigned long *cputime
)
1192 /* This is 'user + sys' time. */
1193 *cputime
= timeval_elapsed (now
->cpu
.ru_utime
, start
->cpu
.ru_utime
) +
1194 timeval_elapsed (now
->cpu
.ru_stime
, start
->cpu
.ru_stime
);
1197 #endif /* HAVE_RUSAGE */
1198 return timeval_elapsed (now
->real
, start
->real
);
1201 /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1202 Note: we are using real (wall clock) time for this calculation.
1203 It could be argued that CPU time may make more sense in certain
1204 contexts. The things to consider are whether the thread may have
1205 blocked (in which case wall time increases, but CPU time does not),
1206 or whether the system is heavily loaded with other processes competing
1207 for CPU time. On balance, wall clock time seems to make sense.
1208 Plus it has the added benefit that gettimeofday should be faster
1209 than calling getrusage. */
1211 thread_should_yield (struct thread
*thread
)
1213 quagga_get_relative (NULL
);
1214 return (timeval_elapsed(relative_time
, thread
->real
) >
1215 THREAD_YIELD_TIME_SLOT
);
1219 thread_getrusage (RUSAGE_T
*r
)
1221 quagga_get_relative (NULL
);
1223 getrusage(RUSAGE_SELF
, &(r
->cpu
));
1225 r
->real
= relative_time
;
1227 #ifdef HAVE_CLOCK_MONOTONIC
1228 /* quagga_get_relative() only updates recent_time if gettimeofday
1229 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1230 * and guarantee to update it before threads are run...
1232 quagga_gettimeofday(&recent_time
);
1233 #endif /* HAVE_CLOCK_MONOTONIC */
1236 /* We check thread consumed time. If the system has getrusage, we'll
1237 use that to get in-depth stats on the performance of the thread in addition
1238 to wall clock time stats from gettimeofday. */
1240 thread_call (struct thread
*thread
)
1242 unsigned long realtime
, cputime
;
1243 RUSAGE_T before
, after
;
1245 /* Cache a pointer to the relevant cpu history thread, if the thread
1246 * does not have it yet.
1248 * Callers submitting 'dummy threads' hence must take care that
1249 * thread->cpu is NULL
1253 struct cpu_thread_history tmp
;
1255 tmp
.func
= thread
->func
;
1256 strcpy(tmp
.funcname
, thread
->funcname
);
1258 thread
->hist
= hash_get (cpu_record
, &tmp
,
1259 (void * (*) (void *))cpu_record_hash_alloc
);
1262 GETRUSAGE (&before
);
1263 thread
->real
= before
.real
;
1265 (*thread
->func
) (thread
);
1269 realtime
= thread_consumed_time (&after
, &before
, &cputime
);
1270 thread
->hist
->real
.total
+= realtime
;
1271 if (thread
->hist
->real
.max
< realtime
)
1272 thread
->hist
->real
.max
= realtime
;
1274 thread
->hist
->cpu
.total
+= cputime
;
1275 if (thread
->hist
->cpu
.max
< cputime
)
1276 thread
->hist
->cpu
.max
= cputime
;
1279 ++(thread
->hist
->total_calls
);
1280 thread
->hist
->types
|= (1 << thread
->add_type
);
1282 #ifdef CONSUMED_TIME_CHECK
1283 if (realtime
> CONSUMED_TIME_CHECK
)
1286 * We have a CPU Hog on our hands.
1287 * Whinge about it now, so we're aware this is yet another task
1290 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1292 (unsigned long) thread
->func
,
1293 realtime
/1000, cputime
/1000);
1295 #endif /* CONSUMED_TIME_CHECK */
1298 /* Execute thread */
1300 funcname_thread_execute (struct thread_master
*m
,
1301 int (*func
)(struct thread
*),
1304 const char* funcname
)
1306 struct thread dummy
;
1308 memset (&dummy
, 0, sizeof (struct thread
));
1310 dummy
.type
= THREAD_EVENT
;
1311 dummy
.add_type
= THREAD_EXECUTE
;
1312 dummy
.master
= NULL
;
1316 strip_funcname (dummy
.funcname
, funcname
);
1317 thread_call (&dummy
);