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
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
;
40 static unsigned short timers_inited
;
42 static struct hash
*cpu_record
= NULL
;
44 /* Struct timeval's tv_usec one second value. */
45 #define TIMER_SECOND_MICRO 1000000L
47 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
48 And change negative values to 0. */
50 timeval_adjust (struct timeval a
)
52 while (a
.tv_usec
>= TIMER_SECOND_MICRO
)
54 a
.tv_usec
-= TIMER_SECOND_MICRO
;
60 a
.tv_usec
+= TIMER_SECOND_MICRO
;
65 /* Change negative timeouts to 0. */
66 a
.tv_sec
= a
.tv_usec
= 0;
72 timeval_subtract (struct timeval a
, struct timeval b
)
76 ret
.tv_usec
= a
.tv_usec
- b
.tv_usec
;
77 ret
.tv_sec
= a
.tv_sec
- b
.tv_sec
;
79 return timeval_adjust (ret
);
83 timeval_cmp (struct timeval a
, struct timeval b
)
85 return (a
.tv_sec
== b
.tv_sec
86 ? a
.tv_usec
- b
.tv_usec
: a
.tv_sec
- b
.tv_sec
);
90 timeval_elapsed (struct timeval a
, struct timeval b
)
92 return (((a
.tv_sec
- b
.tv_sec
) * TIMER_SECOND_MICRO
)
93 + (a
.tv_usec
- b
.tv_usec
));
96 #ifndef HAVE_CLOCK_MONOTONIC
98 quagga_gettimeofday_relative_adjust (void)
101 if (timeval_cmp (recent_time
, last_recent_time
) < 0)
103 relative_time
.tv_sec
++;
104 relative_time
.tv_usec
= 0;
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
);
113 last_recent_time
= recent_time
;
115 #endif /* !HAVE_CLOCK_MONOTONIC */
117 /* gettimeofday wrapper, to keep recent_time updated */
119 quagga_gettimeofday (struct timeval
*tv
)
125 if (!(ret
= gettimeofday (&recent_time
, NULL
)))
130 relative_time_base
= last_recent_time
= recent_time
;
133 /* avoid copy if user passed recent_time pointer.. */
134 if (tv
!= &recent_time
)
142 quagga_get_relative (struct timeval
*tv
)
146 #ifdef HAVE_CLOCK_MONOTONIC
149 if (!(ret
= clock_gettime (CLOCK_MONOTONIC
, &tp
)))
151 relative_time
.tv_sec
= tp
.tv_sec
;
152 relative_time
.tv_usec
= tp
.tv_nsec
/ 1000;
155 #else /* !HAVE_CLOCK_MONOTONIC */
156 if (!(ret
= quagga_gettimeofday (&recent_time
)))
157 quagga_gettimeofday_relative_adjust();
158 #endif /* HAVE_CLOCK_MONOTONIC */
166 /* Get absolute time stamp, but in terms of the internal timer
167 * Could be wrong, but at least won't go back.
170 quagga_real_stabilised (struct timeval
*tv
)
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
);
178 /* Exported Quagga timestamp function.
179 * Modelled on POSIX clock_gettime.
182 quagga_gettime (enum quagga_clkid clkid
, struct timeval
*tv
)
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
);
199 /* time_t value in terms of stabilised absolute time.
200 * replacement for POSIX time()
203 quagga_time (time_t *t
)
206 quagga_real_stabilised (&tv
);
212 /* Public export of recent_relative_time by value */
214 recent_relative_time (void)
216 return relative_time
;
220 cpu_record_hash_key (struct cpu_thread_history
*a
)
222 return (uintptr_t) a
->func
;
226 cpu_record_hash_cmp (const struct cpu_thread_history
*a
,
227 const struct cpu_thread_history
*b
)
229 return a
->func
== b
->func
;
233 cpu_record_hash_alloc (struct cpu_thread_history
*a
)
235 struct cpu_thread_history
*new;
236 new = XCALLOC (MTYPE_THREAD_STATS
, sizeof (struct cpu_thread_history
));
238 new->funcname
= XSTRDUP(MTYPE_THREAD_FUNCNAME
, a
->funcname
);
243 cpu_record_hash_free (void *a
)
245 struct cpu_thread_history
*hist
= a
;
247 XFREE (MTYPE_THREAD_FUNCNAME
, hist
->funcname
);
248 XFREE (MTYPE_THREAD_STATS
, hist
);
252 vty_out_cpu_thread_history(struct vty
* vty
,
253 struct cpu_thread_history
*a
)
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
);
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
);
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
);
276 cpu_record_hash_print(struct hash_backet
*bucket
,
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
;
285 if ( !(a
->types
& *filter
) )
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
;
293 totals
->cpu
.total
+= a
->cpu
.total
;
294 if (totals
->cpu
.max
< a
->cpu
.max
)
295 totals
->cpu
.max
= a
->cpu
.max
;
300 cpu_record_print(struct vty
*vty
, thread_type filter
)
302 struct cpu_thread_history tmp
;
303 void *args
[3] = {&tmp
, vty
, &filter
};
305 memset(&tmp
, 0, sizeof tmp
);
306 tmp
.funcname
= "TOTAL";
310 vty_out(vty
, "%21s %18s %18s%s",
311 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE
);
313 vty_out(vty
, "Runtime(ms) Invoked Avg uSec Max uSecs");
315 vty_out(vty
, " Avg uSec Max uSecs");
317 vty_out(vty
, " Type Thread%s", VTY_NEWLINE
);
318 hash_iterate(cpu_record
,
319 (void(*)(struct hash_backet
*,void*))cpu_record_hash_print
,
322 if (tmp
.total_calls
> 0)
323 vty_out_cpu_thread_history(vty
, &tmp
);
326 DEFUN(show_thread_cpu
,
328 "show thread cpu [FILTER]",
330 "Thread information\n"
332 "Display filter (rwtexb)\n")
335 thread_type filter
= (thread_type
) -1U;
340 while (argv
[0][i
] != '\0')
342 switch ( argv
[0][i
] )
346 filter
|= (1 << THREAD_READ
);
350 filter
|= (1 << THREAD_WRITE
);
354 filter
|= (1 << THREAD_TIMER
);
358 filter
|= (1 << THREAD_EVENT
);
362 filter
|= (1 << THREAD_EXECUTE
);
366 filter
|= (1 << THREAD_BACKGROUND
);
375 vty_out(vty
, "Invalid filter \"%s\" specified,"
376 " must contain at least one of 'RWTEXB'%s",
377 argv
[0], VTY_NEWLINE
);
382 cpu_record_print(vty
, filter
);
386 /* List allocation and head/tail print out. */
388 thread_list_debug (struct thread_list
*list
)
390 printf ("count [%d] head [%p] tail [%p]\n",
391 list
->count
, list
->head
, list
->tail
);
394 /* Debug print for thread_master. */
395 static void __attribute__ ((unused
))
396 thread_master_debug (struct thread_master
*m
)
398 printf ("-----------\n");
399 printf ("readlist : ");
400 thread_list_debug (&m
->read
);
401 printf ("writelist : ");
402 thread_list_debug (&m
->write
);
403 printf ("timerlist : ");
404 thread_list_debug (&m
->timer
);
405 printf ("eventlist : ");
406 thread_list_debug (&m
->event
);
407 printf ("unuselist : ");
408 thread_list_debug (&m
->unuse
);
409 printf ("bgndlist : ");
410 thread_list_debug (&m
->background
);
411 printf ("total alloc: [%ld]\n", m
->alloc
);
412 printf ("-----------\n");
415 /* Allocate new thread master. */
416 struct thread_master
*
417 thread_master_create ()
419 if (cpu_record
== NULL
)
421 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key
,
422 (int (*) (const void *, const void *))cpu_record_hash_cmp
);
424 return (struct thread_master
*) XCALLOC (MTYPE_THREAD_MASTER
,
425 sizeof (struct thread_master
));
428 /* Add a new thread to the list. */
430 thread_list_add (struct thread_list
*list
, struct thread
*thread
)
433 thread
->prev
= list
->tail
;
435 list
->tail
->next
= thread
;
442 /* Add a new thread just before the point. */
444 thread_list_add_before (struct thread_list
*list
,
445 struct thread
*point
,
446 struct thread
*thread
)
448 thread
->next
= point
;
449 thread
->prev
= point
->prev
;
451 point
->prev
->next
= thread
;
454 point
->prev
= thread
;
458 /* Delete a thread from the list. */
459 static struct thread
*
460 thread_list_delete (struct thread_list
*list
, struct thread
*thread
)
463 thread
->next
->prev
= thread
->prev
;
465 list
->tail
= thread
->prev
;
467 thread
->prev
->next
= thread
->next
;
469 list
->head
= thread
->next
;
470 thread
->next
= thread
->prev
= NULL
;
475 /* Move thread to unuse list. */
477 thread_add_unuse (struct thread_master
*m
, struct thread
*thread
)
479 assert (m
!= NULL
&& thread
!= NULL
);
480 assert (thread
->next
== NULL
);
481 assert (thread
->prev
== NULL
);
482 assert (thread
->type
== THREAD_UNUSED
);
483 thread_list_add (&m
->unuse
, thread
);
484 /* XXX: Should we deallocate funcname here? */
487 /* Free all unused thread. */
489 thread_list_free (struct thread_master
*m
, struct thread_list
*list
)
494 for (t
= list
->head
; t
; t
= next
)
498 XFREE (MTYPE_THREAD_FUNCNAME
, t
->funcname
);
499 XFREE (MTYPE_THREAD
, t
);
505 /* Stop thread scheduler. */
507 thread_master_free (struct thread_master
*m
)
509 thread_list_free (m
, &m
->read
);
510 thread_list_free (m
, &m
->write
);
511 thread_list_free (m
, &m
->timer
);
512 thread_list_free (m
, &m
->event
);
513 thread_list_free (m
, &m
->ready
);
514 thread_list_free (m
, &m
->unuse
);
515 thread_list_free (m
, &m
->background
);
517 XFREE (MTYPE_THREAD_MASTER
, m
);
521 hash_clean (cpu_record
, cpu_record_hash_free
);
522 hash_free (cpu_record
);
527 /* Thread list is empty or not. */
529 thread_empty (struct thread_list
*list
)
531 return list
->head
? 0 : 1;
534 /* Delete top of the list and return it. */
535 static struct thread
*
536 thread_trim_head (struct thread_list
*list
)
538 if (!thread_empty (list
))
539 return thread_list_delete (list
, list
->head
);
543 /* Return remain time in second. */
545 thread_timer_remain_second (struct thread
*thread
)
547 quagga_get_relative (NULL
);
549 if (thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
> 0)
550 return thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
;
555 /* Trim blankspace and "()"s */
557 strip_funcname (const char *funcname
)
560 char tmp
, *ret
, *e
, *b
= buff
;
562 strncpy(buff
, funcname
, sizeof(buff
));
563 buff
[ sizeof(buff
) -1] = '\0';
564 e
= buff
+strlen(buff
) -1;
566 /* Wont work for funcname == "Word (explanation)" */
568 while (*b
== ' ' || *b
== '(')
570 while (*e
== ' ' || *e
== ')')
576 ret
= XSTRDUP (MTYPE_THREAD_FUNCNAME
, b
);
582 /* Get new thread. */
583 static struct thread
*
584 thread_get (struct thread_master
*m
, u_char type
,
585 int (*func
) (struct thread
*), void *arg
, const char* funcname
)
587 struct thread
*thread
;
589 if (!thread_empty (&m
->unuse
))
591 thread
= thread_trim_head (&m
->unuse
);
592 if (thread
->funcname
)
593 XFREE(MTYPE_THREAD_FUNCNAME
, thread
->funcname
);
597 thread
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
));
601 thread
->add_type
= type
;
606 thread
->funcname
= strip_funcname(funcname
);
611 /* Add new read thread. */
613 funcname_thread_add_read (struct thread_master
*m
,
614 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
616 struct thread
*thread
;
620 if (FD_ISSET (fd
, &m
->readfd
))
622 zlog (NULL
, LOG_WARNING
, "There is already read fd [%d]", fd
);
626 thread
= thread_get (m
, THREAD_READ
, func
, arg
, funcname
);
627 FD_SET (fd
, &m
->readfd
);
629 thread_list_add (&m
->read
, thread
);
634 /* Add new write thread. */
636 funcname_thread_add_write (struct thread_master
*m
,
637 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
639 struct thread
*thread
;
643 if (FD_ISSET (fd
, &m
->writefd
))
645 zlog (NULL
, LOG_WARNING
, "There is already write fd [%d]", fd
);
649 thread
= thread_get (m
, THREAD_WRITE
, func
, arg
, funcname
);
650 FD_SET (fd
, &m
->writefd
);
652 thread_list_add (&m
->write
, thread
);
657 static struct thread
*
658 funcname_thread_add_timer_timeval (struct thread_master
*m
,
659 int (*func
) (struct thread
*),
662 struct timeval
*time_relative
,
663 const char* funcname
)
665 struct thread
*thread
;
666 struct thread_list
*list
;
667 struct timeval alarm_time
;
672 assert (type
== THREAD_TIMER
|| type
== THREAD_BACKGROUND
);
673 assert (time_relative
);
675 list
= ((type
== THREAD_TIMER
) ? &m
->timer
: &m
->background
);
676 thread
= thread_get (m
, type
, func
, arg
, funcname
);
678 /* Do we need jitter here? */
679 quagga_get_relative (NULL
);
680 alarm_time
.tv_sec
= relative_time
.tv_sec
+ time_relative
->tv_sec
;
681 alarm_time
.tv_usec
= relative_time
.tv_usec
+ time_relative
->tv_usec
;
682 thread
->u
.sands
= timeval_adjust(alarm_time
);
684 /* Sort by timeval. */
685 for (tt
= list
->head
; tt
; tt
= tt
->next
)
686 if (timeval_cmp (thread
->u
.sands
, tt
->u
.sands
) <= 0)
690 thread_list_add_before (list
, tt
, thread
);
692 thread_list_add (list
, thread
);
698 /* Add timer event thread. */
700 funcname_thread_add_timer (struct thread_master
*m
,
701 int (*func
) (struct thread
*),
702 void *arg
, long timer
, const char* funcname
)
711 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
, arg
,
715 /* Add timer event thread with "millisecond" resolution */
717 funcname_thread_add_timer_msec (struct thread_master
*m
,
718 int (*func
) (struct thread
*),
719 void *arg
, long timer
, const char* funcname
)
725 trel
.tv_sec
= timer
/ 1000;
726 trel
.tv_usec
= 1000*(timer
% 1000);
728 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
729 arg
, &trel
, funcname
);
732 /* Add a background thread, with an optional millisec delay */
734 funcname_thread_add_background (struct thread_master
*m
,
735 int (*func
) (struct thread
*),
736 void *arg
, long delay
,
737 const char *funcname
)
745 trel
.tv_sec
= delay
/ 1000;
746 trel
.tv_usec
= 1000*(delay
% 1000);
754 return funcname_thread_add_timer_timeval (m
, func
, THREAD_BACKGROUND
,
755 arg
, &trel
, funcname
);
758 /* Add simple event thread. */
760 funcname_thread_add_event (struct thread_master
*m
,
761 int (*func
) (struct thread
*), void *arg
, int val
, const char* funcname
)
763 struct thread
*thread
;
767 thread
= thread_get (m
, THREAD_EVENT
, func
, arg
, funcname
);
769 thread_list_add (&m
->event
, thread
);
774 /* Cancel thread from scheduler. */
776 thread_cancel (struct thread
*thread
)
778 struct thread_list
*list
;
780 switch (thread
->type
)
783 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->readfd
));
784 FD_CLR (thread
->u
.fd
, &thread
->master
->readfd
);
785 list
= &thread
->master
->read
;
788 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->writefd
));
789 FD_CLR (thread
->u
.fd
, &thread
->master
->writefd
);
790 list
= &thread
->master
->write
;
793 list
= &thread
->master
->timer
;
796 list
= &thread
->master
->event
;
799 list
= &thread
->master
->ready
;
801 case THREAD_BACKGROUND
:
802 list
= &thread
->master
->background
;
808 thread_list_delete (list
, thread
);
809 thread
->type
= THREAD_UNUSED
;
810 thread_add_unuse (thread
->master
, thread
);
813 /* Delete all events which has argument value arg. */
815 thread_cancel_event (struct thread_master
*m
, void *arg
)
817 unsigned int ret
= 0;
818 struct thread
*thread
;
820 thread
= m
->event
.head
;
831 thread_list_delete (&m
->event
, t
);
832 t
->type
= THREAD_UNUSED
;
833 thread_add_unuse (m
, t
);
839 static struct timeval
*
840 thread_timer_wait (struct thread_list
*tlist
, struct timeval
*timer_val
)
842 if (!thread_empty (tlist
))
844 *timer_val
= timeval_subtract (tlist
->head
->u
.sands
, relative_time
);
850 static struct thread
*
851 thread_run (struct thread_master
*m
, struct thread
*thread
,
852 struct thread
*fetch
)
855 thread
->type
= THREAD_UNUSED
;
856 thread
->funcname
= NULL
; /* thread_call will free fetch's copied pointer */
857 thread_add_unuse (m
, thread
);
862 thread_process_fd (struct thread_list
*list
, fd_set
*fdset
, fd_set
*mfdset
)
864 struct thread
*thread
;
870 for (thread
= list
->head
; thread
; thread
= next
)
874 if (FD_ISSET (THREAD_FD (thread
), fdset
))
876 assert (FD_ISSET (THREAD_FD (thread
), mfdset
));
877 FD_CLR(THREAD_FD (thread
), mfdset
);
878 thread_list_delete (list
, thread
);
879 thread_list_add (&thread
->master
->ready
, thread
);
880 thread
->type
= THREAD_READY
;
887 /* Add all timers that have popped to the ready list. */
889 thread_timer_process (struct thread_list
*list
, struct timeval
*timenow
)
891 struct thread
*thread
;
892 unsigned int ready
= 0;
894 for (thread
= list
->head
; thread
; thread
= thread
->next
)
896 if (timeval_cmp (*timenow
, thread
->u
.sands
) < 0)
898 thread_list_delete (list
, thread
);
899 thread
->type
= THREAD_READY
;
900 thread_list_add (&thread
->master
->ready
, thread
);
906 /* Fetch next ready thread. */
908 thread_fetch (struct thread_master
*m
, struct thread
*fetch
)
910 struct thread
*thread
;
914 struct timeval timer_val
;
915 struct timeval timer_val_bg
;
916 struct timeval
*timer_wait
;
917 struct timeval
*timer_wait_bg
;
923 /* Signals are highest priority */
924 quagga_sigevent_process ();
926 /* Normal event are the next highest priority. */
927 if ((thread
= thread_trim_head (&m
->event
)) != NULL
)
928 return thread_run (m
, thread
, fetch
);
930 /* If there are any ready threads from previous scheduler runs,
931 * process top of them.
933 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
934 return thread_run (m
, thread
, fetch
);
936 /* Structure copy. */
938 writefd
= m
->writefd
;
939 exceptfd
= m
->exceptfd
;
941 /* Calculate select wait timer if nothing else to do */
942 quagga_get_relative (NULL
);
943 timer_wait
= thread_timer_wait (&m
->timer
, &timer_val
);
944 timer_wait_bg
= thread_timer_wait (&m
->background
, &timer_val_bg
);
947 (!timer_wait
|| (timeval_cmp (*timer_wait
, *timer_wait_bg
) > 0)))
948 timer_wait
= timer_wait_bg
;
950 num
= select (FD_SETSIZE
, &readfd
, &writefd
, &exceptfd
, timer_wait
);
952 /* Signals should get quick treatment */
956 continue; /* signal received - process it */
957 zlog_warn ("select() error: %s", safe_strerror (errno
));
961 /* Check foreground timers. Historically, they have had higher
962 priority than I/O threads, so let's push them onto the ready
963 list in front of the I/O threads. */
964 quagga_get_relative (NULL
);
965 thread_timer_process (&m
->timer
, &relative_time
);
967 /* Got IO, process it */
970 /* Normal priority read thead. */
971 thread_process_fd (&m
->read
, &readfd
, &m
->readfd
);
973 thread_process_fd (&m
->write
, &writefd
, &m
->writefd
);
977 /* If any threads were made ready above (I/O or foreground timer),
978 perhaps we should avoid adding background timers to the ready
979 list at this time. If this is code is uncommented, then background
980 timer threads will not run unless there is nothing else to do. */
981 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
982 return thread_run (m
, thread
, fetch
);
985 /* Background timer/events, lowest priority */
986 thread_timer_process (&m
->background
, &relative_time
);
988 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
989 return thread_run (m
, thread
, fetch
);
994 thread_consumed_time (RUSAGE_T
*now
, RUSAGE_T
*start
, unsigned long *cputime
)
997 /* This is 'user + sys' time. */
998 *cputime
= timeval_elapsed (now
->cpu
.ru_utime
, start
->cpu
.ru_utime
) +
999 timeval_elapsed (now
->cpu
.ru_stime
, start
->cpu
.ru_stime
);
1002 #endif /* HAVE_RUSAGE */
1003 return timeval_elapsed (now
->real
, start
->real
);
1006 /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1007 Note: we are using real (wall clock) time for this calculation.
1008 It could be argued that CPU time may make more sense in certain
1009 contexts. The things to consider are whether the thread may have
1010 blocked (in which case wall time increases, but CPU time does not),
1011 or whether the system is heavily loaded with other processes competing
1012 for CPU time. On balance, wall clock time seems to make sense.
1013 Plus it has the added benefit that gettimeofday should be faster
1014 than calling getrusage. */
1016 thread_should_yield (struct thread
*thread
)
1018 quagga_get_relative (NULL
);
1019 return (timeval_elapsed(relative_time
, thread
->ru
.real
) >
1020 THREAD_YIELD_TIME_SLOT
);
1024 thread_getrusage (RUSAGE_T
*r
)
1026 quagga_get_relative (NULL
);
1028 getrusage(RUSAGE_SELF
, &(r
->cpu
));
1030 r
->real
= relative_time
;
1032 #ifdef HAVE_CLOCK_MONOTONIC
1033 /* quagga_get_relative() only updates recent_time if gettimeofday
1034 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1035 * and guarantee to update it before threads are run...
1037 quagga_gettimeofday(&recent_time
);
1038 #endif /* HAVE_CLOCK_MONOTONIC */
1041 /* We check thread consumed time. If the system has getrusage, we'll
1042 use that to get in-depth stats on the performance of the thread in addition
1043 to wall clock time stats from gettimeofday. */
1045 thread_call (struct thread
*thread
)
1047 unsigned long realtime
, cputime
;
1050 /* Cache a pointer to the relevant cpu history thread, if the thread
1051 * does not have it yet.
1053 * Callers submitting 'dummy threads' hence must take care that
1054 * thread->cpu is NULL
1058 struct cpu_thread_history tmp
;
1060 tmp
.func
= thread
->func
;
1061 tmp
.funcname
= thread
->funcname
;
1063 thread
->hist
= hash_get (cpu_record
, &tmp
,
1064 (void * (*) (void *))cpu_record_hash_alloc
);
1067 GETRUSAGE (&thread
->ru
);
1069 (*thread
->func
) (thread
);
1073 realtime
= thread_consumed_time (&ru
, &thread
->ru
, &cputime
);
1074 thread
->hist
->real
.total
+= realtime
;
1075 if (thread
->hist
->real
.max
< realtime
)
1076 thread
->hist
->real
.max
= realtime
;
1078 thread
->hist
->cpu
.total
+= cputime
;
1079 if (thread
->hist
->cpu
.max
< cputime
)
1080 thread
->hist
->cpu
.max
= cputime
;
1083 ++(thread
->hist
->total_calls
);
1084 thread
->hist
->types
|= (1 << thread
->add_type
);
1086 #ifdef CONSUMED_TIME_CHECK
1087 if (realtime
> CONSUMED_TIME_CHECK
)
1090 * We have a CPU Hog on our hands.
1091 * Whinge about it now, so we're aware this is yet another task
1094 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1096 (unsigned long) thread
->func
,
1097 realtime
/1000, cputime
/1000);
1099 #endif /* CONSUMED_TIME_CHECK */
1101 XFREE (MTYPE_THREAD_FUNCNAME
, thread
->funcname
);
1104 /* Execute thread */
1106 funcname_thread_execute (struct thread_master
*m
,
1107 int (*func
)(struct thread
*),
1110 const char* funcname
)
1112 struct thread dummy
;
1114 memset (&dummy
, 0, sizeof (struct thread
));
1116 dummy
.type
= THREAD_EVENT
;
1117 dummy
.add_type
= THREAD_EXECUTE
;
1118 dummy
.master
= NULL
;
1122 dummy
.funcname
= strip_funcname (funcname
);
1123 thread_call (&dummy
);
1125 XFREE (MTYPE_THREAD_FUNCNAME
, dummy
.funcname
);