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
25 #include <sys/resource.h>
35 DEFINE_MTYPE_STATIC(LIB
, THREAD
, "Thread")
36 DEFINE_MTYPE_STATIC(LIB
, THREAD_MASTER
, "Thread master")
37 DEFINE_MTYPE_STATIC(LIB
, THREAD_STATS
, "Thread stats")
39 #if defined(__APPLE__)
40 #include <mach/mach.h>
41 #include <mach/mach_time.h>
44 /* Recent absolute time of day */
45 struct timeval recent_time
;
46 /* Relative time, since startup */
47 static struct timeval relative_time
;
49 static struct hash
*cpu_record
= NULL
;
51 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
52 And change negative values to 0. */
54 timeval_adjust (struct timeval a
)
56 while (a
.tv_usec
>= TIMER_SECOND_MICRO
)
58 a
.tv_usec
-= TIMER_SECOND_MICRO
;
64 a
.tv_usec
+= TIMER_SECOND_MICRO
;
69 /* Change negative timeouts to 0. */
70 a
.tv_sec
= a
.tv_usec
= 0;
76 timeval_subtract (struct timeval a
, struct timeval b
)
80 ret
.tv_usec
= a
.tv_usec
- b
.tv_usec
;
81 ret
.tv_sec
= a
.tv_sec
- b
.tv_sec
;
83 return timeval_adjust (ret
);
87 timeval_cmp (struct timeval a
, struct timeval b
)
89 return (a
.tv_sec
== b
.tv_sec
90 ? a
.tv_usec
- b
.tv_usec
: a
.tv_sec
- b
.tv_sec
);
94 timeval_elapsed (struct timeval a
, struct timeval b
)
96 return (((a
.tv_sec
- b
.tv_sec
) * TIMER_SECOND_MICRO
)
97 + (a
.tv_usec
- b
.tv_usec
));
100 /* gettimeofday wrapper, to keep recent_time updated */
102 quagga_gettimeofday (struct timeval
*tv
)
108 if (!(ret
= gettimeofday (&recent_time
, NULL
)))
110 /* avoid copy if user passed recent_time pointer.. */
111 if (tv
!= &recent_time
)
119 quagga_get_relative (struct timeval
*tv
)
123 #ifdef HAVE_CLOCK_MONOTONIC
126 if (!(ret
= clock_gettime (CLOCK_MONOTONIC
, &tp
)))
128 relative_time
.tv_sec
= tp
.tv_sec
;
129 relative_time
.tv_usec
= tp
.tv_nsec
/ 1000;
132 #elif defined(__APPLE__)
136 static mach_timebase_info_data_t timebase_info
;
138 ticks
= mach_absolute_time();
139 if (timebase_info
.denom
== 0)
140 mach_timebase_info(&timebase_info
);
142 useconds
= ticks
* timebase_info
.numer
/ timebase_info
.denom
/ 1000;
143 relative_time
.tv_sec
= useconds
/ 1000000;
144 relative_time
.tv_usec
= useconds
% 1000000;
148 #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
149 #error no monotonic clock on this system
150 #endif /* HAVE_CLOCK_MONOTONIC */
158 /* Exported Quagga timestamp function.
159 * Modelled on POSIX clock_gettime.
162 quagga_gettime (enum quagga_clkid clkid
, struct timeval
*tv
)
166 case QUAGGA_CLK_MONOTONIC
:
167 return quagga_get_relative (tv
);
175 quagga_monotime (void)
178 quagga_get_relative(&tv
);
182 /* Public export of recent_relative_time by value */
184 recent_relative_time (void)
186 return relative_time
;
190 cpu_record_hash_key (struct cpu_thread_history
*a
)
192 return (uintptr_t) a
->func
;
196 cpu_record_hash_cmp (const struct cpu_thread_history
*a
,
197 const struct cpu_thread_history
*b
)
199 return a
->func
== b
->func
;
203 cpu_record_hash_alloc (struct cpu_thread_history
*a
)
205 struct cpu_thread_history
*new;
206 new = XCALLOC (MTYPE_THREAD_STATS
, sizeof (struct cpu_thread_history
));
208 new->funcname
= a
->funcname
;
213 cpu_record_hash_free (void *a
)
215 struct cpu_thread_history
*hist
= a
;
217 XFREE (MTYPE_THREAD_STATS
, hist
);
221 vty_out_cpu_thread_history(struct vty
* vty
,
222 struct cpu_thread_history
*a
)
224 vty_out(vty
, "%10ld.%03ld %9d %8ld %9ld %8ld %9ld",
225 a
->cpu
.total
/1000, a
->cpu
.total
%1000, a
->total_calls
,
226 a
->cpu
.total
/a
->total_calls
, a
->cpu
.max
,
227 a
->real
.total
/a
->total_calls
, a
->real
.max
);
228 vty_out(vty
, " %c%c%c%c%c%c %s%s",
229 a
->types
& (1 << THREAD_READ
) ? 'R':' ',
230 a
->types
& (1 << THREAD_WRITE
) ? 'W':' ',
231 a
->types
& (1 << THREAD_TIMER
) ? 'T':' ',
232 a
->types
& (1 << THREAD_EVENT
) ? 'E':' ',
233 a
->types
& (1 << THREAD_EXECUTE
) ? 'X':' ',
234 a
->types
& (1 << THREAD_BACKGROUND
) ? 'B' : ' ',
235 a
->funcname
, VTY_NEWLINE
);
239 cpu_record_hash_print(struct hash_backet
*bucket
,
242 struct cpu_thread_history
*totals
= args
[0];
243 struct vty
*vty
= args
[1];
244 thread_type
*filter
= args
[2];
245 struct cpu_thread_history
*a
= bucket
->data
;
247 if ( !(a
->types
& *filter
) )
249 vty_out_cpu_thread_history(vty
,a
);
250 totals
->total_calls
+= a
->total_calls
;
251 totals
->real
.total
+= a
->real
.total
;
252 if (totals
->real
.max
< a
->real
.max
)
253 totals
->real
.max
= a
->real
.max
;
254 totals
->cpu
.total
+= a
->cpu
.total
;
255 if (totals
->cpu
.max
< a
->cpu
.max
)
256 totals
->cpu
.max
= a
->cpu
.max
;
260 cpu_record_print(struct vty
*vty
, thread_type filter
)
262 struct cpu_thread_history tmp
;
263 void *args
[3] = {&tmp
, vty
, &filter
};
265 memset(&tmp
, 0, sizeof tmp
);
266 tmp
.funcname
= "TOTAL";
269 vty_out(vty
, "%21s %18s %18s%s",
270 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE
);
271 vty_out(vty
, " Runtime(ms) Invoked Avg uSec Max uSecs");
272 vty_out(vty
, " Avg uSec Max uSecs");
273 vty_out(vty
, " Type Thread%s", VTY_NEWLINE
);
274 hash_iterate(cpu_record
,
275 (void(*)(struct hash_backet
*,void*))cpu_record_hash_print
,
278 if (tmp
.total_calls
> 0)
279 vty_out_cpu_thread_history(vty
, &tmp
);
282 DEFUN (show_thread_cpu
,
284 "show thread cpu [FILTER]",
286 "Thread information\n"
288 "Display filter (rwtexb)\n")
291 thread_type filter
= (thread_type
) -1U;
296 while (argv
[0][i
] != '\0')
298 switch ( argv
[0][i
] )
302 filter
|= (1 << THREAD_READ
);
306 filter
|= (1 << THREAD_WRITE
);
310 filter
|= (1 << THREAD_TIMER
);
314 filter
|= (1 << THREAD_EVENT
);
318 filter
|= (1 << THREAD_EXECUTE
);
322 filter
|= (1 << THREAD_BACKGROUND
);
331 vty_out(vty
, "Invalid filter \"%s\" specified,"
332 " must contain at least one of 'RWTEXB'%s",
333 argv
[0], VTY_NEWLINE
);
338 cpu_record_print(vty
, filter
);
343 cpu_record_hash_clear (struct hash_backet
*bucket
,
346 thread_type
*filter
= args
;
347 struct cpu_thread_history
*a
= bucket
->data
;
349 if ( !(a
->types
& *filter
) )
352 hash_release (cpu_record
, bucket
->data
);
356 cpu_record_clear (thread_type filter
)
358 thread_type
*tmp
= &filter
;
359 hash_iterate (cpu_record
,
360 (void (*) (struct hash_backet
*,void*)) cpu_record_hash_clear
,
364 DEFUN (clear_thread_cpu
,
365 clear_thread_cpu_cmd
,
366 "clear thread cpu [FILTER]",
367 "Clear stored data\n"
368 "Thread information\n"
370 "Display filter (rwtexb)\n")
373 thread_type filter
= (thread_type
) -1U;
378 while (argv
[0][i
] != '\0')
380 switch ( argv
[0][i
] )
384 filter
|= (1 << THREAD_READ
);
388 filter
|= (1 << THREAD_WRITE
);
392 filter
|= (1 << THREAD_TIMER
);
396 filter
|= (1 << THREAD_EVENT
);
400 filter
|= (1 << THREAD_EXECUTE
);
404 filter
|= (1 << THREAD_BACKGROUND
);
413 vty_out(vty
, "Invalid filter \"%s\" specified,"
414 " must contain at least one of 'RWTEXB'%s",
415 argv
[0], VTY_NEWLINE
);
420 cpu_record_clear (filter
);
425 thread_timer_cmp(void *a
, void *b
)
427 struct thread
*thread_a
= a
;
428 struct thread
*thread_b
= b
;
430 long cmp
= timeval_cmp(thread_a
->u
.sands
, thread_b
->u
.sands
);
440 thread_timer_update(void *node
, int actual_position
)
442 struct thread
*thread
= node
;
444 thread
->index
= actual_position
;
447 /* Allocate new thread master. */
448 struct thread_master
*
449 thread_master_create (void)
451 struct thread_master
*rv
;
454 getrlimit(RLIMIT_NOFILE
, &limit
);
456 if (cpu_record
== NULL
)
458 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key
,
459 (int (*) (const void *, const void *))cpu_record_hash_cmp
);
461 rv
= XCALLOC (MTYPE_THREAD_MASTER
, sizeof (struct thread_master
));
467 rv
->fd_limit
= (int)limit
.rlim_cur
;
468 rv
->read
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
*) * rv
->fd_limit
);
469 if (rv
->read
== NULL
)
471 XFREE (MTYPE_THREAD_MASTER
, rv
);
475 rv
->write
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
*) * rv
->fd_limit
);
476 if (rv
->write
== NULL
)
478 XFREE (MTYPE_THREAD
, rv
->read
);
479 XFREE (MTYPE_THREAD_MASTER
, rv
);
483 /* Initialize the timer queues */
484 rv
->timer
= pqueue_create();
485 rv
->background
= pqueue_create();
486 rv
->timer
->cmp
= rv
->background
->cmp
= thread_timer_cmp
;
487 rv
->timer
->update
= rv
->background
->update
= thread_timer_update
;
489 #if defined(HAVE_POLL)
490 rv
->handler
.pfdsize
= rv
->fd_limit
;
491 rv
->handler
.pfdcount
= 0;
492 rv
->handler
.pfds
= (struct pollfd
*) malloc (sizeof (struct pollfd
) * rv
->handler
.pfdsize
);
493 memset (rv
->handler
.pfds
, 0, sizeof (struct pollfd
) * rv
->handler
.pfdsize
);
498 /* Add a new thread to the list. */
500 thread_list_add (struct thread_list
*list
, struct thread
*thread
)
503 thread
->prev
= list
->tail
;
505 list
->tail
->next
= thread
;
512 /* Delete a thread from the list. */
513 static struct thread
*
514 thread_list_delete (struct thread_list
*list
, struct thread
*thread
)
517 thread
->next
->prev
= thread
->prev
;
519 list
->tail
= thread
->prev
;
521 thread
->prev
->next
= thread
->next
;
523 list
->head
= thread
->next
;
524 thread
->next
= thread
->prev
= NULL
;
530 thread_delete_fd (struct thread
**thread_array
, struct thread
*thread
)
532 thread_array
[thread
->u
.fd
] = NULL
;
536 thread_add_fd (struct thread
**thread_array
, struct thread
*thread
)
538 thread_array
[thread
->u
.fd
] = thread
;
541 /* Thread list is empty or not. */
543 thread_empty (struct thread_list
*list
)
545 return list
->head
? 0 : 1;
548 /* Delete top of the list and return it. */
549 static struct thread
*
550 thread_trim_head (struct thread_list
*list
)
552 if (!thread_empty (list
))
553 return thread_list_delete (list
, list
->head
);
557 /* Move thread to unuse list. */
559 thread_add_unuse (struct thread_master
*m
, struct thread
*thread
)
561 assert (m
!= NULL
&& thread
!= NULL
);
562 assert (thread
->next
== NULL
);
563 assert (thread
->prev
== NULL
);
564 assert (thread
->type
== THREAD_UNUSED
);
565 thread_list_add (&m
->unuse
, thread
);
568 /* Free all unused thread. */
570 thread_list_free (struct thread_master
*m
, struct thread_list
*list
)
575 for (t
= list
->head
; t
; t
= next
)
578 XFREE (MTYPE_THREAD
, t
);
585 thread_array_free (struct thread_master
*m
, struct thread
**thread_array
)
590 for (index
= 0; index
< m
->fd_limit
; ++index
)
592 t
= thread_array
[index
];
595 thread_array
[index
] = NULL
;
596 XFREE (MTYPE_THREAD
, t
);
600 XFREE (MTYPE_THREAD
, thread_array
);
604 thread_queue_free (struct thread_master
*m
, struct pqueue
*queue
)
608 for (i
= 0; i
< queue
->size
; i
++)
609 XFREE(MTYPE_THREAD
, queue
->array
[i
]);
611 m
->alloc
-= queue
->size
;
612 pqueue_delete(queue
);
616 * thread_master_free_unused
618 * As threads are finished with they are put on the
619 * unuse list for later reuse.
620 * If we are shutting down, Free up unused threads
621 * So we can see if we forget to shut anything off
624 thread_master_free_unused (struct thread_master
*m
)
627 while ((t
= thread_trim_head(&m
->unuse
)) != NULL
)
629 XFREE(MTYPE_THREAD
, t
);
633 /* Stop thread scheduler. */
635 thread_master_free (struct thread_master
*m
)
637 thread_array_free (m
, m
->read
);
638 thread_array_free (m
, m
->write
);
639 thread_queue_free (m
, m
->timer
);
640 thread_list_free (m
, &m
->event
);
641 thread_list_free (m
, &m
->ready
);
642 thread_list_free (m
, &m
->unuse
);
643 thread_queue_free (m
, m
->background
);
645 #if defined(HAVE_POLL)
646 XFREE (MTYPE_THREAD_MASTER
, m
->handler
.pfds
);
648 XFREE (MTYPE_THREAD_MASTER
, m
);
652 hash_clean (cpu_record
, cpu_record_hash_free
);
653 hash_free (cpu_record
);
658 /* Return remain time in second. */
660 thread_timer_remain_second (struct thread
*thread
)
662 quagga_get_relative (NULL
);
664 if (thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
> 0)
665 return thread
->u
.sands
.tv_sec
- relative_time
.tv_sec
;
670 #define debugargdef const char *funcname, const char *schedfrom, int fromln
671 #define debugargpass funcname, schedfrom, fromln
674 thread_timer_remain(struct thread
*thread
)
676 quagga_get_relative(NULL
);
678 return timeval_subtract(thread
->u
.sands
, relative_time
);
681 /* Get new thread. */
682 static struct thread
*
683 thread_get (struct thread_master
*m
, u_char type
,
684 int (*func
) (struct thread
*), void *arg
, debugargdef
)
686 struct thread
*thread
= thread_trim_head (&m
->unuse
);
690 thread
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
));
694 thread
->add_type
= type
;
699 thread
->yield
= THREAD_YIELD_TIME_SLOT
; /* default */
701 thread
->funcname
= funcname
;
702 thread
->schedfrom
= schedfrom
;
703 thread
->schedfrom_line
= fromln
;
708 #if defined (HAVE_POLL)
710 #define fd_copy_fd_set(X) (X)
712 /* generic add thread function */
713 static struct thread
*
714 generic_thread_add(struct thread_master
*m
, int (*func
) (struct thread
*),
715 void *arg
, int fd
, int dir
, debugargdef
)
717 struct thread
*thread
;
722 if (dir
== THREAD_READ
)
724 event
= (POLLIN
| POLLHUP
);
729 event
= (POLLOUT
| POLLHUP
);
733 nfds_t queuepos
= m
->handler
.pfdcount
;
735 for (i
=0; i
<m
->handler
.pfdcount
; i
++)
736 if (m
->handler
.pfds
[i
].fd
== fd
)
742 /* is there enough space for a new fd? */
743 assert (queuepos
< m
->handler
.pfdsize
);
745 thread
= thread_get (m
, type
, func
, arg
, debugargpass
);
746 m
->handler
.pfds
[queuepos
].fd
= fd
;
747 m
->handler
.pfds
[queuepos
].events
|= event
;
748 if (queuepos
== m
->handler
.pfdcount
)
749 m
->handler
.pfdcount
++;
755 #define fd_copy_fd_set(X) (X)
759 fd_select (struct thread_master
*m
, int size
, thread_fd_set
*read
, thread_fd_set
*write
, thread_fd_set
*except
, struct timeval
*timer_wait
)
762 #if defined(HAVE_POLL)
763 /* recalc timeout for poll. Attention NULL pointer is no timeout with
764 select, where with poll no timeount is -1 */
766 if (timer_wait
!= NULL
)
767 timeout
= (timer_wait
->tv_sec
*1000) + (timer_wait
->tv_usec
/1000);
769 num
= poll (m
->handler
.pfds
, m
->handler
.pfdcount
+ m
->handler
.pfdcountsnmp
, timeout
);
771 num
= select (size
, read
, write
, except
, timer_wait
);
778 fd_is_set (struct thread
*thread
, thread_fd_set
*fdset
, int pos
)
780 #if defined(HAVE_POLL)
783 return FD_ISSET (THREAD_FD (thread
), fdset
);
788 fd_clear_read_write (struct thread
*thread
)
790 #if !defined(HAVE_POLL)
791 thread_fd_set
*fdset
= NULL
;
792 int fd
= THREAD_FD (thread
);
794 if (thread
->type
== THREAD_READ
)
795 fdset
= &thread
->master
->handler
.readfd
;
797 fdset
= &thread
->master
->handler
.writefd
;
799 if (!FD_ISSET (fd
, fdset
))
807 /* Add new read thread. */
809 funcname_thread_add_read_write (int dir
, struct thread_master
*m
,
810 int (*func
) (struct thread
*), void *arg
, int fd
,
813 struct thread
*thread
= NULL
;
815 #if !defined(HAVE_POLL)
816 thread_fd_set
*fdset
= NULL
;
817 if (dir
== THREAD_READ
)
818 fdset
= &m
->handler
.readfd
;
820 fdset
= &m
->handler
.writefd
;
823 #if defined (HAVE_POLL)
824 thread
= generic_thread_add(m
, func
, arg
, fd
, dir
, debugargpass
);
829 if (FD_ISSET (fd
, fdset
))
831 zlog (NULL
, LOG_WARNING
, "There is already %s fd [%d]", (dir
= THREAD_READ
) ? "read" : "write", fd
);
836 thread
= thread_get (m
, dir
, func
, arg
, debugargpass
);
840 if (dir
== THREAD_READ
)
841 thread_add_fd (m
->read
, thread
);
843 thread_add_fd (m
->write
, thread
);
848 static struct thread
*
849 funcname_thread_add_timer_timeval (struct thread_master
*m
,
850 int (*func
) (struct thread
*),
853 struct timeval
*time_relative
,
856 struct thread
*thread
;
857 struct pqueue
*queue
;
858 struct timeval alarm_time
;
862 assert (type
== THREAD_TIMER
|| type
== THREAD_BACKGROUND
);
863 assert (time_relative
);
865 queue
= ((type
== THREAD_TIMER
) ? m
->timer
: m
->background
);
866 thread
= thread_get (m
, type
, func
, arg
, debugargpass
);
868 /* Do we need jitter here? */
869 quagga_get_relative (NULL
);
870 alarm_time
.tv_sec
= relative_time
.tv_sec
+ time_relative
->tv_sec
;
871 alarm_time
.tv_usec
= relative_time
.tv_usec
+ time_relative
->tv_usec
;
872 thread
->u
.sands
= timeval_adjust(alarm_time
);
874 pqueue_enqueue(thread
, queue
);
879 /* Add timer event thread. */
881 funcname_thread_add_timer (struct thread_master
*m
,
882 int (*func
) (struct thread
*),
883 void *arg
, long timer
,
893 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
, arg
,
894 &trel
, debugargpass
);
897 /* Add timer event thread with "millisecond" resolution */
899 funcname_thread_add_timer_msec (struct thread_master
*m
,
900 int (*func
) (struct thread
*),
901 void *arg
, long timer
,
908 trel
.tv_sec
= timer
/ 1000;
909 trel
.tv_usec
= 1000*(timer
% 1000);
911 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
912 arg
, &trel
, debugargpass
);
915 /* Add timer event thread with "millisecond" resolution */
917 funcname_thread_add_timer_tv (struct thread_master
*m
,
918 int (*func
) (struct thread
*),
919 void *arg
, struct timeval
*tv
,
922 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
923 arg
, tv
, debugargpass
);
926 /* Add a background thread, with an optional millisec delay */
928 funcname_thread_add_background (struct thread_master
*m
,
929 int (*func
) (struct thread
*),
930 void *arg
, long delay
,
939 trel
.tv_sec
= delay
/ 1000;
940 trel
.tv_usec
= 1000*(delay
% 1000);
948 return funcname_thread_add_timer_timeval (m
, func
, THREAD_BACKGROUND
,
949 arg
, &trel
, debugargpass
);
952 /* Add simple event thread. */
954 funcname_thread_add_event (struct thread_master
*m
,
955 int (*func
) (struct thread
*), void *arg
, int val
,
958 struct thread
*thread
;
962 thread
= thread_get (m
, THREAD_EVENT
, func
, arg
, debugargpass
);
964 thread_list_add (&m
->event
, thread
);
970 thread_cancel_read_or_write (struct thread
*thread
, short int state
)
972 #if defined(HAVE_POLL)
975 for (i
=0;i
<thread
->master
->handler
.pfdcount
;++i
)
976 if (thread
->master
->handler
.pfds
[i
].fd
== thread
->u
.fd
)
978 thread
->master
->handler
.pfds
[i
].events
&= ~(state
);
980 /* remove thread fds from pfd list */
981 if (thread
->master
->handler
.pfds
[i
].events
== 0)
983 memmove(thread
->master
->handler
.pfds
+i
,
984 thread
->master
->handler
.pfds
+i
+1,
985 (thread
->master
->handler
.pfdsize
-i
-1) * sizeof(struct pollfd
));
986 thread
->master
->handler
.pfdcount
--;
992 fd_clear_read_write (thread
);
995 /* Cancel thread from scheduler. */
997 thread_cancel (struct thread
*thread
)
999 struct thread_list
*list
= NULL
;
1000 struct pqueue
*queue
= NULL
;
1001 struct thread
**thread_array
= NULL
;
1003 switch (thread
->type
)
1006 #if defined (HAVE_POLL)
1007 thread_cancel_read_or_write (thread
, POLLIN
| POLLHUP
);
1009 thread_cancel_read_or_write (thread
, 0);
1011 thread_array
= thread
->master
->read
;
1014 #if defined (HAVE_POLL)
1015 thread_cancel_read_or_write (thread
, POLLOUT
| POLLHUP
);
1017 thread_cancel_read_or_write (thread
, 0);
1019 thread_array
= thread
->master
->write
;
1022 queue
= thread
->master
->timer
;
1025 list
= &thread
->master
->event
;
1028 list
= &thread
->master
->ready
;
1030 case THREAD_BACKGROUND
:
1031 queue
= thread
->master
->background
;
1040 assert(thread
->index
>= 0);
1041 assert(thread
== queue
->array
[thread
->index
]);
1042 pqueue_remove_at(thread
->index
, queue
);
1046 thread_list_delete (list
, thread
);
1048 else if (thread_array
)
1050 thread_delete_fd (thread_array
, thread
);
1054 assert(!"Thread should be either in queue or list or array!");
1057 thread
->type
= THREAD_UNUSED
;
1058 thread_add_unuse (thread
->master
, thread
);
1061 /* Delete all events which has argument value arg. */
1063 thread_cancel_event (struct thread_master
*m
, void *arg
)
1065 unsigned int ret
= 0;
1066 struct thread
*thread
;
1068 thread
= m
->event
.head
;
1079 thread_list_delete (&m
->event
, t
);
1080 t
->type
= THREAD_UNUSED
;
1081 thread_add_unuse (m
, t
);
1085 /* thread can be on the ready list too */
1086 thread
= m
->ready
.head
;
1097 thread_list_delete (&m
->ready
, t
);
1098 t
->type
= THREAD_UNUSED
;
1099 thread_add_unuse (m
, t
);
1105 static struct timeval
*
1106 thread_timer_wait (struct pqueue
*queue
, struct timeval
*timer_val
)
1110 struct thread
*next_timer
= queue
->array
[0];
1111 *timer_val
= timeval_subtract (next_timer
->u
.sands
, relative_time
);
1117 static struct thread
*
1118 thread_run (struct thread_master
*m
, struct thread
*thread
,
1119 struct thread
*fetch
)
1122 thread
->type
= THREAD_UNUSED
;
1123 thread_add_unuse (m
, thread
);
1128 thread_process_fds_helper (struct thread_master
*m
, struct thread
*thread
, thread_fd_set
*fdset
, short int state
, int pos
)
1130 struct thread
**thread_array
;
1135 if (thread
->type
== THREAD_READ
)
1136 thread_array
= m
->read
;
1138 thread_array
= m
->write
;
1140 if (fd_is_set (thread
, fdset
, pos
))
1142 fd_clear_read_write (thread
);
1143 thread_delete_fd (thread_array
, thread
);
1144 thread_list_add (&m
->ready
, thread
);
1145 thread
->type
= THREAD_READY
;
1146 #if defined(HAVE_POLL)
1147 thread
->master
->handler
.pfds
[pos
].events
&= ~(state
);
1154 #if defined(HAVE_POLL)
1156 #if defined(HAVE_SNMP)
1157 /* add snmp fds to poll set */
1159 add_snmp_pollfds(struct thread_master
*m
, fd_set
*snmpfds
, int fdsetsize
)
1162 m
->handler
.pfdcountsnmp
= m
->handler
.pfdcount
;
1163 /* cycle trough fds and add neccessary fds to poll set */
1164 for (i
=0;i
<fdsetsize
;++i
)
1166 if (FD_ISSET(i
, snmpfds
))
1168 assert (m
->handler
.pfdcountsnmp
<= m
->handler
.pfdsize
);
1170 m
->handler
.pfds
[m
->handler
.pfdcountsnmp
].fd
= i
;
1171 m
->handler
.pfds
[m
->handler
.pfdcountsnmp
].events
= POLLIN
;
1172 m
->handler
.pfdcountsnmp
++;
1178 /* check poll events */
1180 check_pollfds(struct thread_master
*m
, fd_set
*readfd
, int num
)
1184 for (i
= 0; i
< m
->handler
.pfdcount
&& ready
< num
; ++i
)
1186 /* no event for current fd? immideatly continue */
1187 if(m
->handler
.pfds
[i
].revents
== 0)
1192 /* POLLIN / POLLOUT process event */
1193 if (m
->handler
.pfds
[i
].revents
& POLLIN
)
1194 thread_process_fds_helper(m
, m
->read
[m
->handler
.pfds
[i
].fd
], NULL
, POLLIN
, i
);
1195 if (m
->handler
.pfds
[i
].revents
& POLLOUT
)
1196 thread_process_fds_helper(m
, m
->write
[m
->handler
.pfds
[i
].fd
], NULL
, POLLOUT
, i
);
1198 /* remove fd from list on POLLNVAL */
1199 if (m
->handler
.pfds
[i
].revents
& POLLNVAL
||
1200 m
->handler
.pfds
[i
].revents
& POLLHUP
)
1202 memmove(m
->handler
.pfds
+i
,
1203 m
->handler
.pfds
+i
+1,
1204 (m
->handler
.pfdsize
-i
-1) * sizeof(struct pollfd
));
1205 m
->handler
.pfdcount
--;
1209 m
->handler
.pfds
[i
].revents
= 0;
1215 thread_process_fds (struct thread_master
*m
, thread_fd_set
*rset
, thread_fd_set
*wset
, int num
)
1217 #if defined (HAVE_POLL)
1218 check_pollfds (m
, rset
, num
);
1220 int ready
= 0, index
;
1222 for (index
= 0; index
< m
->fd_limit
&& ready
< num
; ++index
)
1224 ready
+= thread_process_fds_helper (m
, m
->read
[index
], rset
, 0, 0);
1225 ready
+= thread_process_fds_helper (m
, m
->write
[index
], wset
, 0, 0);
1230 /* Add all timers that have popped to the ready list. */
1232 thread_timer_process (struct pqueue
*queue
, struct timeval
*timenow
)
1234 struct thread
*thread
;
1235 unsigned int ready
= 0;
1239 thread
= queue
->array
[0];
1240 if (timeval_cmp (*timenow
, thread
->u
.sands
) < 0)
1242 pqueue_dequeue(queue
);
1243 thread
->type
= THREAD_READY
;
1244 thread_list_add (&thread
->master
->ready
, thread
);
1250 /* process a list en masse, e.g. for event thread lists */
1252 thread_process (struct thread_list
*list
)
1254 struct thread
*thread
;
1255 struct thread
*next
;
1256 unsigned int ready
= 0;
1258 for (thread
= list
->head
; thread
; thread
= next
)
1260 next
= thread
->next
;
1261 thread_list_delete (list
, thread
);
1262 thread
->type
= THREAD_READY
;
1263 thread_list_add (&thread
->master
->ready
, thread
);
1270 /* Fetch next ready thread. */
1272 thread_fetch (struct thread_master
*m
, struct thread
*fetch
)
1274 struct thread
*thread
;
1275 thread_fd_set readfd
;
1276 thread_fd_set writefd
;
1277 thread_fd_set exceptfd
;
1278 struct timeval timer_val
= { .tv_sec
= 0, .tv_usec
= 0 };
1279 struct timeval timer_val_bg
;
1280 struct timeval
*timer_wait
= &timer_val
;
1281 struct timeval
*timer_wait_bg
;
1287 /* Signals pre-empt everything */
1288 quagga_sigevent_process ();
1290 /* Drain the ready queue of already scheduled jobs, before scheduling
1293 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1294 return thread_run (m
, thread
, fetch
);
1296 /* To be fair to all kinds of threads, and avoid starvation, we
1297 * need to be careful to consider all thread types for scheduling
1298 * in each quanta. I.e. we should not return early from here on.
1301 /* Normal event are the next highest priority. */
1302 thread_process (&m
->event
);
1304 /* Structure copy. */
1305 #if !defined(HAVE_POLL)
1306 readfd
= fd_copy_fd_set(m
->handler
.readfd
);
1307 writefd
= fd_copy_fd_set(m
->handler
.writefd
);
1308 exceptfd
= fd_copy_fd_set(m
->handler
.exceptfd
);
1311 /* Calculate select wait timer if nothing else to do */
1312 if (m
->ready
.count
== 0)
1314 quagga_get_relative (NULL
);
1315 timer_wait
= thread_timer_wait (m
->timer
, &timer_val
);
1316 timer_wait_bg
= thread_timer_wait (m
->background
, &timer_val_bg
);
1318 if (timer_wait_bg
&&
1319 (!timer_wait
|| (timeval_cmp (*timer_wait
, *timer_wait_bg
) > 0)))
1320 timer_wait
= timer_wait_bg
;
1323 num
= fd_select (m
, FD_SETSIZE
, &readfd
, &writefd
, &exceptfd
, timer_wait
);
1325 /* Signals should get quick treatment */
1329 continue; /* signal received - process it */
1330 zlog_warn ("select() error: %s", safe_strerror (errno
));
1334 /* Check foreground timers. Historically, they have had higher
1335 priority than I/O threads, so let's push them onto the ready
1336 list in front of the I/O threads. */
1337 quagga_get_relative (NULL
);
1338 thread_timer_process (m
->timer
, &relative_time
);
1340 /* Got IO, process it */
1342 thread_process_fds (m
, &readfd
, &writefd
, num
);
1345 /* If any threads were made ready above (I/O or foreground timer),
1346 perhaps we should avoid adding background timers to the ready
1347 list at this time. If this is code is uncommented, then background
1348 timer threads will not run unless there is nothing else to do. */
1349 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1350 return thread_run (m
, thread
, fetch
);
1353 /* Background timer/events, lowest priority */
1354 thread_timer_process (m
->background
, &relative_time
);
1356 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1357 return thread_run (m
, thread
, fetch
);
1362 thread_consumed_time (RUSAGE_T
*now
, RUSAGE_T
*start
, unsigned long *cputime
)
1364 /* This is 'user + sys' time. */
1365 *cputime
= timeval_elapsed (now
->cpu
.ru_utime
, start
->cpu
.ru_utime
) +
1366 timeval_elapsed (now
->cpu
.ru_stime
, start
->cpu
.ru_stime
);
1367 return timeval_elapsed (now
->real
, start
->real
);
1370 /* We should aim to yield after yield milliseconds, which defaults
1371 to THREAD_YIELD_TIME_SLOT .
1372 Note: we are using real (wall clock) time for this calculation.
1373 It could be argued that CPU time may make more sense in certain
1374 contexts. The things to consider are whether the thread may have
1375 blocked (in which case wall time increases, but CPU time does not),
1376 or whether the system is heavily loaded with other processes competing
1377 for CPU time. On balance, wall clock time seems to make sense.
1378 Plus it has the added benefit that gettimeofday should be faster
1379 than calling getrusage. */
1381 thread_should_yield (struct thread
*thread
)
1383 quagga_get_relative (NULL
);
1384 return (timeval_elapsed(relative_time
, thread
->real
) >
1389 thread_set_yield_time (struct thread
*thread
, unsigned long yield_time
)
1391 thread
->yield
= yield_time
;
1395 thread_getrusage (RUSAGE_T
*r
)
1397 quagga_get_relative (NULL
);
1398 getrusage(RUSAGE_SELF
, &(r
->cpu
));
1399 r
->real
= relative_time
;
1401 #ifdef HAVE_CLOCK_MONOTONIC
1402 /* quagga_get_relative() only updates recent_time if gettimeofday
1403 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1404 * and guarantee to update it before threads are run...
1406 quagga_gettimeofday(&recent_time
);
1407 #endif /* HAVE_CLOCK_MONOTONIC */
1410 struct thread
*thread_current
= NULL
;
1412 /* We check thread consumed time. If the system has getrusage, we'll
1413 use that to get in-depth stats on the performance of the thread in addition
1414 to wall clock time stats from gettimeofday. */
1416 thread_call (struct thread
*thread
)
1418 unsigned long realtime
, cputime
;
1419 RUSAGE_T before
, after
;
1421 /* Cache a pointer to the relevant cpu history thread, if the thread
1422 * does not have it yet.
1424 * Callers submitting 'dummy threads' hence must take care that
1425 * thread->cpu is NULL
1429 struct cpu_thread_history tmp
;
1431 tmp
.func
= thread
->func
;
1432 tmp
.funcname
= thread
->funcname
;
1434 thread
->hist
= hash_get (cpu_record
, &tmp
,
1435 (void * (*) (void *))cpu_record_hash_alloc
);
1438 GETRUSAGE (&before
);
1439 thread
->real
= before
.real
;
1441 thread_current
= thread
;
1442 (*thread
->func
) (thread
);
1443 thread_current
= NULL
;
1447 realtime
= thread_consumed_time (&after
, &before
, &cputime
);
1448 thread
->hist
->real
.total
+= realtime
;
1449 if (thread
->hist
->real
.max
< realtime
)
1450 thread
->hist
->real
.max
= realtime
;
1451 thread
->hist
->cpu
.total
+= cputime
;
1452 if (thread
->hist
->cpu
.max
< cputime
)
1453 thread
->hist
->cpu
.max
= cputime
;
1455 ++(thread
->hist
->total_calls
);
1456 thread
->hist
->types
|= (1 << thread
->add_type
);
1458 #ifdef CONSUMED_TIME_CHECK
1459 if (realtime
> CONSUMED_TIME_CHECK
)
1462 * We have a CPU Hog on our hands.
1463 * Whinge about it now, so we're aware this is yet another task
1466 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1468 (unsigned long) thread
->func
,
1469 realtime
/1000, cputime
/1000);
1471 #endif /* CONSUMED_TIME_CHECK */
1474 /* Execute thread */
1476 funcname_thread_execute (struct thread_master
*m
,
1477 int (*func
)(struct thread
*),
1482 struct thread dummy
;
1484 memset (&dummy
, 0, sizeof (struct thread
));
1486 dummy
.type
= THREAD_EVENT
;
1487 dummy
.add_type
= THREAD_EXECUTE
;
1488 dummy
.master
= NULL
;
1493 dummy
.funcname
= funcname
;
1494 dummy
.schedfrom
= schedfrom
;
1495 dummy
.schedfrom_line
= fromln
;
1497 thread_call (&dummy
);