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 vty_out_cpu_thread_history(struct vty
* vty
,
244 struct cpu_thread_history
*a
)
247 vty_out(vty
, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
248 a
->cpu
.total
/1000, a
->cpu
.total
%1000, a
->total_calls
,
249 a
->cpu
.total
/a
->total_calls
, a
->cpu
.max
,
250 a
->real
.total
/a
->total_calls
, a
->real
.max
);
252 vty_out(vty
, "%7ld.%03ld %9d %8ld %9ld",
253 a
->real
.total
/1000, a
->real
.total
%1000, a
->total_calls
,
254 a
->real
.total
/a
->total_calls
, a
->real
.max
);
256 vty_out(vty
, " %c%c%c%c%c%c %s%s",
257 a
->types
& (1 << THREAD_READ
) ? 'R':' ',
258 a
->types
& (1 << THREAD_WRITE
) ? 'W':' ',
259 a
->types
& (1 << THREAD_TIMER
) ? 'T':' ',
260 a
->types
& (1 << THREAD_EVENT
) ? 'E':' ',
261 a
->types
& (1 << THREAD_EXECUTE
) ? 'X':' ',
262 a
->types
& (1 << THREAD_BACKGROUND
) ? 'B' : ' ',
263 a
->funcname
, VTY_NEWLINE
);
267 cpu_record_hash_print(struct hash_backet
*bucket
,
270 struct cpu_thread_history
*totals
= args
[0];
271 struct vty
*vty
= args
[1];
272 unsigned char *filter
= args
[2];
273 struct cpu_thread_history
*a
= bucket
->data
;
276 if ( !(a
->types
& *filter
) )
278 vty_out_cpu_thread_history(vty
,a
);
279 totals
->total_calls
+= a
->total_calls
;
280 totals
->real
.total
+= a
->real
.total
;
281 if (totals
->real
.max
< a
->real
.max
)
282 totals
->real
.max
= a
->real
.max
;
284 totals
->cpu
.total
+= a
->cpu
.total
;
285 if (totals
->cpu
.max
< a
->cpu
.max
)
286 totals
->cpu
.max
= a
->cpu
.max
;
291 cpu_record_print(struct vty
*vty
, unsigned char filter
)
293 struct cpu_thread_history tmp
;
294 void *args
[3] = {&tmp
, vty
, &filter
};
296 memset(&tmp
, 0, sizeof tmp
);
297 tmp
.funcname
= "TOTAL";
301 vty_out(vty
, "%21s %18s %18s%s",
302 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE
);
304 vty_out(vty
, "Runtime(ms) Invoked Avg uSec Max uSecs");
306 vty_out(vty
, " Avg uSec Max uSecs");
308 vty_out(vty
, " Type Thread%s", VTY_NEWLINE
);
309 hash_iterate(cpu_record
,
310 (void(*)(struct hash_backet
*,void*))cpu_record_hash_print
,
313 if (tmp
.total_calls
> 0)
314 vty_out_cpu_thread_history(vty
, &tmp
);
317 DEFUN(show_thread_cpu
,
319 "show thread cpu [FILTER]",
321 "Thread information\n"
323 "Display filter (rwtexb)\n")
326 unsigned char filter
= 0xff;
331 while (argv
[0][i
] != '\0')
333 switch ( argv
[0][i
] )
337 filter
|= (1 << THREAD_READ
);
341 filter
|= (1 << THREAD_WRITE
);
345 filter
|= (1 << THREAD_TIMER
);
349 filter
|= (1 << THREAD_EVENT
);
353 filter
|= (1 << THREAD_EXECUTE
);
357 filter
|= (1 << THREAD_BACKGROUND
);
366 vty_out(vty
, "Invalid filter \"%s\" specified,"
367 " must contain at least one of 'RWTEXB'%s",
368 argv
[0], VTY_NEWLINE
);
373 cpu_record_print(vty
, filter
);
377 /* List allocation and head/tail print out. */
379 thread_list_debug (struct thread_list
*list
)
381 printf ("count [%d] head [%p] tail [%p]\n",
382 list
->count
, list
->head
, list
->tail
);
385 /* Debug print for thread_master. */
386 static void __attribute__ ((unused
))
387 thread_master_debug (struct thread_master
*m
)
389 printf ("-----------\n");
390 printf ("readlist : ");
391 thread_list_debug (&m
->read
);
392 printf ("writelist : ");
393 thread_list_debug (&m
->write
);
394 printf ("timerlist : ");
395 thread_list_debug (&m
->timer
);
396 printf ("eventlist : ");
397 thread_list_debug (&m
->event
);
398 printf ("unuselist : ");
399 thread_list_debug (&m
->unuse
);
400 printf ("bgndlist : ");
401 thread_list_debug (&m
->background
);
402 printf ("total alloc: [%ld]\n", m
->alloc
);
403 printf ("-----------\n");
406 /* Allocate new thread master. */
407 struct thread_master
*
408 thread_master_create ()
410 if (cpu_record
== NULL
)
412 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key
,
413 (int (*) (const void *, const void *))cpu_record_hash_cmp
);
415 return (struct thread_master
*) XCALLOC (MTYPE_THREAD_MASTER
,
416 sizeof (struct thread_master
));
419 /* Add a new thread to the list. */
421 thread_list_add (struct thread_list
*list
, struct thread
*thread
)
424 thread
->prev
= list
->tail
;
426 list
->tail
->next
= thread
;
433 /* Add a new thread just before the point. */
435 thread_list_add_before (struct thread_list
*list
,
436 struct thread
*point
,
437 struct thread
*thread
)
439 thread
->next
= point
;
440 thread
->prev
= point
->prev
;
442 point
->prev
->next
= thread
;
445 point
->prev
= thread
;
449 /* Delete a thread from the list. */
450 static struct thread
*
451 thread_list_delete (struct thread_list
*list
, struct thread
*thread
)
454 thread
->next
->prev
= thread
->prev
;
456 list
->tail
= thread
->prev
;
458 thread
->prev
->next
= thread
->next
;
460 list
->head
= thread
->next
;
461 thread
->next
= thread
->prev
= NULL
;
466 /* Move thread to unuse list. */
468 thread_add_unuse (struct thread_master
*m
, struct thread
*thread
)
470 assert (m
!= NULL
&& thread
!= NULL
);
471 assert (thread
->next
== NULL
);
472 assert (thread
->prev
== NULL
);
473 assert (thread
->type
== THREAD_UNUSED
);
474 thread_list_add (&m
->unuse
, thread
);
475 /* XXX: Should we deallocate funcname here? */
478 /* Free all unused thread. */
480 thread_list_free (struct thread_master
*m
, struct thread_list
*list
)
485 for (t
= list
->head
; t
; t
= next
)
488 XFREE (MTYPE_THREAD_FUNCNAME
, t
->funcname
);
489 XFREE (MTYPE_THREAD
, t
);
495 /* Stop thread scheduler. */
497 thread_master_free (struct thread_master
*m
)
499 thread_list_free (m
, &m
->read
);
500 thread_list_free (m
, &m
->write
);
501 thread_list_free (m
, &m
->timer
);
502 thread_list_free (m
, &m
->event
);
503 thread_list_free (m
, &m
->ready
);
504 thread_list_free (m
, &m
->unuse
);
505 thread_list_free (m
, &m
->background
);
507 XFREE (MTYPE_THREAD_MASTER
, m
);
510 /* Thread list is empty or not. */
512 thread_empty (struct thread_list
*list
)
514 return list
->head
? 0 : 1;
517 /* Delete top of the list and return it. */
518 static struct thread
*
519 thread_trim_head (struct thread_list
*list
)
521 if (!thread_empty (list
))
522 return thread_list_delete (list
, list
->head
);
526 /* Return remain time in second. */
528 thread_timer_remain_second (struct thread
*thread
)
530 quagga_get_relative (NULL
);
532 if (thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
> 0)
533 return thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
;
538 /* Trim blankspace and "()"s */
540 strip_funcname (const char *funcname
)
543 char tmp
, *ret
, *e
, *b
= buff
;
545 strncpy(buff
, funcname
, sizeof(buff
));
546 buff
[ sizeof(buff
) -1] = '\0';
547 e
= buff
+strlen(buff
) -1;
549 /* Wont work for funcname == "Word (explanation)" */
551 while (*b
== ' ' || *b
== '(')
553 while (*e
== ' ' || *e
== ')')
559 ret
= XSTRDUP (MTYPE_THREAD_FUNCNAME
, b
);
565 /* Get new thread. */
566 static struct thread
*
567 thread_get (struct thread_master
*m
, u_char type
,
568 int (*func
) (struct thread
*), void *arg
, const char* funcname
)
570 struct thread
*thread
;
572 if (!thread_empty (&m
->unuse
))
574 thread
= thread_trim_head (&m
->unuse
);
575 if (thread
->funcname
)
576 XFREE(MTYPE_THREAD_FUNCNAME
, thread
->funcname
);
580 thread
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
));
584 thread
->add_type
= type
;
589 thread
->funcname
= strip_funcname(funcname
);
594 /* Add new read thread. */
596 funcname_thread_add_read (struct thread_master
*m
,
597 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
599 struct thread
*thread
;
603 if (FD_ISSET (fd
, &m
->readfd
))
605 zlog (NULL
, LOG_WARNING
, "There is already read fd [%d]", fd
);
609 thread
= thread_get (m
, THREAD_READ
, func
, arg
, funcname
);
610 FD_SET (fd
, &m
->readfd
);
612 thread_list_add (&m
->read
, thread
);
617 /* Add new write thread. */
619 funcname_thread_add_write (struct thread_master
*m
,
620 int (*func
) (struct thread
*), void *arg
, int fd
, const char* funcname
)
622 struct thread
*thread
;
626 if (FD_ISSET (fd
, &m
->writefd
))
628 zlog (NULL
, LOG_WARNING
, "There is already write fd [%d]", fd
);
632 thread
= thread_get (m
, THREAD_WRITE
, func
, arg
, funcname
);
633 FD_SET (fd
, &m
->writefd
);
635 thread_list_add (&m
->write
, thread
);
640 static struct thread
*
641 funcname_thread_add_timer_timeval (struct thread_master
*m
,
642 int (*func
) (struct thread
*),
645 struct timeval
*time_relative
,
646 const char* funcname
)
648 struct thread
*thread
;
649 struct thread_list
*list
;
650 struct timeval alarm_time
;
655 assert (type
== THREAD_TIMER
|| type
== THREAD_BACKGROUND
);
656 assert (time_relative
);
658 list
= ((type
== THREAD_TIMER
) ? &m
->timer
: &m
->background
);
659 thread
= thread_get (m
, type
, func
, arg
, funcname
);
661 /* Do we need jitter here? */
662 quagga_get_relative (NULL
);
663 alarm_time
.tv_sec
= relative_time
.tv_sec
+ time_relative
->tv_sec
;
664 alarm_time
.tv_usec
= relative_time
.tv_usec
+ time_relative
->tv_usec
;
665 thread
->u
.sands
= timeval_adjust(alarm_time
);
667 /* Sort by timeval. */
668 for (tt
= list
->head
; tt
; tt
= tt
->next
)
669 if (timeval_cmp (thread
->u
.sands
, tt
->u
.sands
) <= 0)
673 thread_list_add_before (list
, tt
, thread
);
675 thread_list_add (list
, thread
);
681 /* Add timer event thread. */
683 funcname_thread_add_timer (struct thread_master
*m
,
684 int (*func
) (struct thread
*),
685 void *arg
, long timer
, const char* funcname
)
694 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
, arg
,
698 /* Add timer event thread with "millisecond" resolution */
700 funcname_thread_add_timer_msec (struct thread_master
*m
,
701 int (*func
) (struct thread
*),
702 void *arg
, long timer
, const char* funcname
)
708 trel
.tv_sec
= timer
/ 1000;
709 trel
.tv_usec
= 1000*(timer
% 1000);
711 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
712 arg
, &trel
, funcname
);
715 /* Add a background thread, with an optional millisec delay */
717 funcname_thread_add_background (struct thread_master
*m
,
718 int (*func
) (struct thread
*),
719 void *arg
, long delay
,
720 const char *funcname
)
728 trel
.tv_sec
= delay
/ 1000;
729 trel
.tv_usec
= 1000*(delay
% 1000);
737 return funcname_thread_add_timer_timeval (m
, func
, THREAD_BACKGROUND
,
738 arg
, &trel
, funcname
);
741 /* Add simple event thread. */
743 funcname_thread_add_event (struct thread_master
*m
,
744 int (*func
) (struct thread
*), void *arg
, int val
, const char* funcname
)
746 struct thread
*thread
;
750 thread
= thread_get (m
, THREAD_EVENT
, func
, arg
, funcname
);
752 thread_list_add (&m
->event
, thread
);
757 /* Cancel thread from scheduler. */
759 thread_cancel (struct thread
*thread
)
761 struct thread_list
*list
;
763 switch (thread
->type
)
766 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->readfd
));
767 FD_CLR (thread
->u
.fd
, &thread
->master
->readfd
);
768 list
= &thread
->master
->read
;
771 assert (FD_ISSET (thread
->u
.fd
, &thread
->master
->writefd
));
772 FD_CLR (thread
->u
.fd
, &thread
->master
->writefd
);
773 list
= &thread
->master
->write
;
776 list
= &thread
->master
->timer
;
779 list
= &thread
->master
->event
;
782 list
= &thread
->master
->ready
;
784 case THREAD_BACKGROUND
:
785 list
= &thread
->master
->background
;
791 thread_list_delete (list
, thread
);
792 thread
->type
= THREAD_UNUSED
;
793 thread_add_unuse (thread
->master
, thread
);
796 /* Delete all events which has argument value arg. */
798 thread_cancel_event (struct thread_master
*m
, void *arg
)
800 unsigned int ret
= 0;
801 struct thread
*thread
;
803 thread
= m
->event
.head
;
814 thread_list_delete (&m
->event
, t
);
815 t
->type
= THREAD_UNUSED
;
816 thread_add_unuse (m
, t
);
822 static struct timeval
*
823 thread_timer_wait (struct thread_list
*tlist
, struct timeval
*timer_val
)
825 if (!thread_empty (tlist
))
827 *timer_val
= timeval_subtract (tlist
->head
->u
.sands
, relative_time
);
833 static struct thread
*
834 thread_run (struct thread_master
*m
, struct thread
*thread
,
835 struct thread
*fetch
)
838 thread
->type
= THREAD_UNUSED
;
839 thread_add_unuse (m
, thread
);
844 thread_process_fd (struct thread_list
*list
, fd_set
*fdset
, fd_set
*mfdset
)
846 struct thread
*thread
;
852 for (thread
= list
->head
; thread
; thread
= next
)
856 if (FD_ISSET (THREAD_FD (thread
), fdset
))
858 assert (FD_ISSET (THREAD_FD (thread
), mfdset
));
859 FD_CLR(THREAD_FD (thread
), mfdset
);
860 thread_list_delete (list
, thread
);
861 thread_list_add (&thread
->master
->ready
, thread
);
862 thread
->type
= THREAD_READY
;
869 /* Add all timers that have popped to the ready list. */
871 thread_timer_process (struct thread_list
*list
, struct timeval
*timenow
)
873 struct thread
*thread
;
874 unsigned int ready
= 0;
876 for (thread
= list
->head
; thread
; thread
= thread
->next
)
878 if (timeval_cmp (*timenow
, thread
->u
.sands
) < 0)
880 thread_list_delete (list
, thread
);
881 thread
->type
= THREAD_READY
;
882 thread_list_add (&thread
->master
->ready
, thread
);
888 /* Fetch next ready thread. */
890 thread_fetch (struct thread_master
*m
, struct thread
*fetch
)
892 struct thread
*thread
;
896 struct timeval timer_val
;
897 struct timeval timer_val_bg
;
898 struct timeval
*timer_wait
;
899 struct timeval
*timer_wait_bg
;
905 /* Signals are highest priority */
906 quagga_sigevent_process ();
908 /* Normal event are the next highest priority. */
909 if ((thread
= thread_trim_head (&m
->event
)) != NULL
)
910 return thread_run (m
, thread
, fetch
);
912 /* If there are any ready threads from previous scheduler runs,
913 * process top of them.
915 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
916 return thread_run (m
, thread
, fetch
);
918 /* Structure copy. */
920 writefd
= m
->writefd
;
921 exceptfd
= m
->exceptfd
;
923 /* Calculate select wait timer if nothing else to do */
924 quagga_get_relative (NULL
);
925 timer_wait
= thread_timer_wait (&m
->timer
, &timer_val
);
926 timer_wait_bg
= thread_timer_wait (&m
->background
, &timer_val_bg
);
929 (!timer_wait
|| (timeval_cmp (*timer_wait
, *timer_wait_bg
) > 0)))
930 timer_wait
= timer_wait_bg
;
932 num
= select (FD_SETSIZE
, &readfd
, &writefd
, &exceptfd
, timer_wait
);
934 /* Signals should get quick treatment */
938 continue; /* signal received - process it */
939 zlog_warn ("select() error: %s", safe_strerror (errno
));
943 /* Check foreground timers. Historically, they have had higher
944 priority than I/O threads, so let's push them onto the ready
945 list in front of the I/O threads. */
946 quagga_get_relative (NULL
);
947 thread_timer_process (&m
->timer
, &relative_time
);
949 /* Got IO, process it */
952 /* Normal priority read thead. */
953 thread_process_fd (&m
->read
, &readfd
, &m
->readfd
);
955 thread_process_fd (&m
->write
, &writefd
, &m
->writefd
);
959 /* If any threads were made ready above (I/O or foreground timer),
960 perhaps we should avoid adding background timers to the ready
961 list at this time. If this is code is uncommented, then background
962 timer threads will not run unless there is nothing else to do. */
963 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
964 return thread_run (m
, thread
, fetch
);
967 /* Background timer/events, lowest priority */
968 thread_timer_process (&m
->background
, &relative_time
);
970 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
971 return thread_run (m
, thread
, fetch
);
976 thread_consumed_time (RUSAGE_T
*now
, RUSAGE_T
*start
, unsigned long *cputime
)
979 /* This is 'user + sys' time. */
980 *cputime
= timeval_elapsed (now
->cpu
.ru_utime
, start
->cpu
.ru_utime
) +
981 timeval_elapsed (now
->cpu
.ru_stime
, start
->cpu
.ru_stime
);
984 #endif /* HAVE_RUSAGE */
985 return timeval_elapsed (now
->real
, start
->real
);
988 /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
989 Note: we are using real (wall clock) time for this calculation.
990 It could be argued that CPU time may make more sense in certain
991 contexts. The things to consider are whether the thread may have
992 blocked (in which case wall time increases, but CPU time does not),
993 or whether the system is heavily loaded with other processes competing
994 for CPU time. On balance, wall clock time seems to make sense.
995 Plus it has the added benefit that gettimeofday should be faster
996 than calling getrusage. */
998 thread_should_yield (struct thread
*thread
)
1000 quagga_get_relative (NULL
);
1001 return (timeval_elapsed(relative_time
, thread
->ru
.real
) >
1002 THREAD_YIELD_TIME_SLOT
);
1006 thread_getrusage (RUSAGE_T
*r
)
1008 quagga_get_relative (NULL
);
1010 getrusage(RUSAGE_SELF
, &(r
->cpu
));
1012 r
->real
= relative_time
;
1014 #ifdef HAVE_CLOCK_MONOTONIC
1015 /* quagga_get_relative() only updates recent_time if gettimeofday
1016 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1017 * and guarantee to update it before threads are run...
1019 quagga_gettimeofday(&recent_time
);
1020 #endif /* HAVE_CLOCK_MONOTONIC */
1023 /* We check thread consumed time. If the system has getrusage, we'll
1024 use that to get in-depth stats on the performance of the thread in addition
1025 to wall clock time stats from gettimeofday. */
1027 thread_call (struct thread
*thread
)
1029 unsigned long realtime
, cputime
;
1032 /* Cache a pointer to the relevant cpu history thread, if the thread
1033 * does not have it yet.
1035 * Callers submitting 'dummy threads' hence must take care that
1036 * thread->cpu is NULL
1040 struct cpu_thread_history tmp
;
1042 tmp
.func
= thread
->func
;
1043 tmp
.funcname
= thread
->funcname
;
1045 thread
->hist
= hash_get (cpu_record
, &tmp
,
1046 (void * (*) (void *))cpu_record_hash_alloc
);
1049 GETRUSAGE (&thread
->ru
);
1051 (*thread
->func
) (thread
);
1055 realtime
= thread_consumed_time (&ru
, &thread
->ru
, &cputime
);
1056 thread
->hist
->real
.total
+= realtime
;
1057 if (thread
->hist
->real
.max
< realtime
)
1058 thread
->hist
->real
.max
= realtime
;
1060 thread
->hist
->cpu
.total
+= cputime
;
1061 if (thread
->hist
->cpu
.max
< cputime
)
1062 thread
->hist
->cpu
.max
= cputime
;
1065 ++(thread
->hist
->total_calls
);
1066 thread
->hist
->types
|= (1 << thread
->add_type
);
1068 #ifdef CONSUMED_TIME_CHECK
1069 if (realtime
> CONSUMED_TIME_CHECK
)
1072 * We have a CPU Hog on our hands.
1073 * Whinge about it now, so we're aware this is yet another task
1076 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1078 (unsigned long) thread
->func
,
1079 realtime
/1000, cputime
/1000);
1081 #endif /* CONSUMED_TIME_CHECK */
1084 /* Execute thread */
1086 funcname_thread_execute (struct thread_master
*m
,
1087 int (*func
)(struct thread
*),
1090 const char* funcname
)
1092 struct thread dummy
;
1094 memset (&dummy
, 0, sizeof (struct thread
));
1096 dummy
.type
= THREAD_EVENT
;
1097 dummy
.add_type
= THREAD_EXECUTE
;
1098 dummy
.master
= NULL
;
1102 dummy
.funcname
= strip_funcname (funcname
);
1103 thread_call (&dummy
);
1105 XFREE (MTYPE_THREAD_FUNCNAME
, dummy
.funcname
);