]>
git.proxmox.com Git - mirror_frr.git/blob - lib/thread.c
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 /* Relative time, since startup */
45 static struct hash
*cpu_record
= NULL
;
48 timeval_elapsed (struct timeval a
, struct timeval b
)
50 return (((a
.tv_sec
- b
.tv_sec
) * TIMER_SECOND_MICRO
)
51 + (a
.tv_usec
- b
.tv_usec
));
55 cpu_record_hash_key (struct cpu_thread_history
*a
)
57 return (uintptr_t) a
->func
;
61 cpu_record_hash_cmp (const struct cpu_thread_history
*a
,
62 const struct cpu_thread_history
*b
)
64 return a
->func
== b
->func
;
68 cpu_record_hash_alloc (struct cpu_thread_history
*a
)
70 struct cpu_thread_history
*new;
71 new = XCALLOC (MTYPE_THREAD_STATS
, sizeof (struct cpu_thread_history
));
73 new->funcname
= a
->funcname
;
78 cpu_record_hash_free (void *a
)
80 struct cpu_thread_history
*hist
= a
;
82 XFREE (MTYPE_THREAD_STATS
, hist
);
86 vty_out_cpu_thread_history(struct vty
* vty
,
87 struct cpu_thread_history
*a
)
89 vty_out(vty
, "%5d %10ld.%03ld %9d %8ld %9ld %8ld %9ld",
90 a
->total_active
, a
->cpu
.total
/1000, a
->cpu
.total
%1000, a
->total_calls
,
91 a
->cpu
.total
/a
->total_calls
, a
->cpu
.max
,
92 a
->real
.total
/a
->total_calls
, a
->real
.max
);
93 vty_out(vty
, " %c%c%c%c%c%c %s%s",
94 a
->types
& (1 << THREAD_READ
) ? 'R':' ',
95 a
->types
& (1 << THREAD_WRITE
) ? 'W':' ',
96 a
->types
& (1 << THREAD_TIMER
) ? 'T':' ',
97 a
->types
& (1 << THREAD_EVENT
) ? 'E':' ',
98 a
->types
& (1 << THREAD_EXECUTE
) ? 'X':' ',
99 a
->types
& (1 << THREAD_BACKGROUND
) ? 'B' : ' ',
100 a
->funcname
, VTY_NEWLINE
);
104 cpu_record_hash_print(struct hash_backet
*bucket
,
107 struct cpu_thread_history
*totals
= args
[0];
108 struct vty
*vty
= args
[1];
109 thread_type
*filter
= args
[2];
110 struct cpu_thread_history
*a
= bucket
->data
;
112 if ( !(a
->types
& *filter
) )
114 vty_out_cpu_thread_history(vty
,a
);
115 totals
->total_active
+= a
->total_active
;
116 totals
->total_calls
+= a
->total_calls
;
117 totals
->real
.total
+= a
->real
.total
;
118 if (totals
->real
.max
< a
->real
.max
)
119 totals
->real
.max
= a
->real
.max
;
120 totals
->cpu
.total
+= a
->cpu
.total
;
121 if (totals
->cpu
.max
< a
->cpu
.max
)
122 totals
->cpu
.max
= a
->cpu
.max
;
126 cpu_record_print(struct vty
*vty
, thread_type filter
)
128 struct cpu_thread_history tmp
;
129 void *args
[3] = {&tmp
, vty
, &filter
};
131 memset(&tmp
, 0, sizeof tmp
);
132 tmp
.funcname
= "TOTAL";
135 vty_out(vty
, "%21s %18s %18s%s",
136 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE
);
137 vty_out(vty
, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
138 vty_out(vty
, " Avg uSec Max uSecs");
139 vty_out(vty
, " Type Thread%s", VTY_NEWLINE
);
140 hash_iterate(cpu_record
,
141 (void(*)(struct hash_backet
*,void*))cpu_record_hash_print
,
144 if (tmp
.total_calls
> 0)
145 vty_out_cpu_thread_history(vty
, &tmp
);
148 DEFUN (show_thread_cpu
,
150 "show thread cpu [FILTER]",
152 "Thread information\n"
154 "Display filter (rwtexb)\n")
158 thread_type filter
= (thread_type
) -1U;
163 while (argv
[idx_filter
]->arg
[i
] != '\0')
165 switch ( argv
[idx_filter
]->arg
[i
] )
169 filter
|= (1 << THREAD_READ
);
173 filter
|= (1 << THREAD_WRITE
);
177 filter
|= (1 << THREAD_TIMER
);
181 filter
|= (1 << THREAD_EVENT
);
185 filter
|= (1 << THREAD_EXECUTE
);
189 filter
|= (1 << THREAD_BACKGROUND
);
198 vty_out(vty
, "Invalid filter \"%s\" specified,"
199 " must contain at least one of 'RWTEXB'%s",
200 argv
[idx_filter
]->arg
, VTY_NEWLINE
);
205 cpu_record_print(vty
, filter
);
210 cpu_record_hash_clear (struct hash_backet
*bucket
,
213 thread_type
*filter
= args
;
214 struct cpu_thread_history
*a
= bucket
->data
;
216 if ( !(a
->types
& *filter
) )
219 hash_release (cpu_record
, bucket
->data
);
223 cpu_record_clear (thread_type filter
)
225 thread_type
*tmp
= &filter
;
226 hash_iterate (cpu_record
,
227 (void (*) (struct hash_backet
*,void*)) cpu_record_hash_clear
,
231 DEFUN (clear_thread_cpu
,
232 clear_thread_cpu_cmd
,
233 "clear thread cpu [FILTER]",
234 "Clear stored data\n"
235 "Thread information\n"
237 "Display filter (rwtexb)\n")
241 thread_type filter
= (thread_type
) -1U;
246 while (argv
[idx_filter
]->arg
[i
] != '\0')
248 switch ( argv
[idx_filter
]->arg
[i
] )
252 filter
|= (1 << THREAD_READ
);
256 filter
|= (1 << THREAD_WRITE
);
260 filter
|= (1 << THREAD_TIMER
);
264 filter
|= (1 << THREAD_EVENT
);
268 filter
|= (1 << THREAD_EXECUTE
);
272 filter
|= (1 << THREAD_BACKGROUND
);
281 vty_out(vty
, "Invalid filter \"%s\" specified,"
282 " must contain at least one of 'RWTEXB'%s",
283 argv
[idx_filter
]->arg
, VTY_NEWLINE
);
288 cpu_record_clear (filter
);
293 thread_cmd_init (void)
295 install_element (VIEW_NODE
, &show_thread_cpu_cmd
);
296 install_element (ENABLE_NODE
, &clear_thread_cpu_cmd
);
300 thread_timer_cmp(void *a
, void *b
)
302 struct thread
*thread_a
= a
;
303 struct thread
*thread_b
= b
;
305 if (timercmp (&thread_a
->u
.sands
, &thread_b
->u
.sands
, <))
307 if (timercmp (&thread_a
->u
.sands
, &thread_b
->u
.sands
, >))
313 thread_timer_update(void *node
, int actual_position
)
315 struct thread
*thread
= node
;
317 thread
->index
= actual_position
;
320 /* Allocate new thread master. */
321 struct thread_master
*
322 thread_master_create (void)
324 struct thread_master
*rv
;
327 getrlimit(RLIMIT_NOFILE
, &limit
);
329 if (cpu_record
== NULL
)
331 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key
,
332 (int (*) (const void *, const void *))cpu_record_hash_cmp
);
334 rv
= XCALLOC (MTYPE_THREAD_MASTER
, sizeof (struct thread_master
));
340 rv
->fd_limit
= (int)limit
.rlim_cur
;
341 rv
->read
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
*) * rv
->fd_limit
);
342 if (rv
->read
== NULL
)
344 XFREE (MTYPE_THREAD_MASTER
, rv
);
348 rv
->write
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
*) * rv
->fd_limit
);
349 if (rv
->write
== NULL
)
351 XFREE (MTYPE_THREAD
, rv
->read
);
352 XFREE (MTYPE_THREAD_MASTER
, rv
);
356 /* Initialize the timer queues */
357 rv
->timer
= pqueue_create();
358 rv
->background
= pqueue_create();
359 rv
->timer
->cmp
= rv
->background
->cmp
= thread_timer_cmp
;
360 rv
->timer
->update
= rv
->background
->update
= thread_timer_update
;
362 #if defined(HAVE_POLL)
363 rv
->handler
.pfdsize
= rv
->fd_limit
;
364 rv
->handler
.pfdcount
= 0;
365 rv
->handler
.pfds
= (struct pollfd
*) malloc (sizeof (struct pollfd
) * rv
->handler
.pfdsize
);
366 memset (rv
->handler
.pfds
, 0, sizeof (struct pollfd
) * rv
->handler
.pfdsize
);
371 /* Add a new thread to the list. */
373 thread_list_add (struct thread_list
*list
, struct thread
*thread
)
376 thread
->prev
= list
->tail
;
378 list
->tail
->next
= thread
;
385 /* Delete a thread from the list. */
386 static struct thread
*
387 thread_list_delete (struct thread_list
*list
, struct thread
*thread
)
390 thread
->next
->prev
= thread
->prev
;
392 list
->tail
= thread
->prev
;
394 thread
->prev
->next
= thread
->next
;
396 list
->head
= thread
->next
;
397 thread
->next
= thread
->prev
= NULL
;
403 thread_delete_fd (struct thread
**thread_array
, struct thread
*thread
)
405 thread_array
[thread
->u
.fd
] = NULL
;
409 thread_add_fd (struct thread
**thread_array
, struct thread
*thread
)
411 thread_array
[thread
->u
.fd
] = thread
;
414 /* Thread list is empty or not. */
416 thread_empty (struct thread_list
*list
)
418 return list
->head
? 0 : 1;
421 /* Delete top of the list and return it. */
422 static struct thread
*
423 thread_trim_head (struct thread_list
*list
)
425 if (!thread_empty (list
))
426 return thread_list_delete (list
, list
->head
);
430 /* Move thread to unuse list. */
432 thread_add_unuse (struct thread_master
*m
, struct thread
*thread
)
434 assert (m
!= NULL
&& thread
!= NULL
);
435 assert (thread
->next
== NULL
);
436 assert (thread
->prev
== NULL
);
438 thread
->type
= THREAD_UNUSED
;
439 thread
->hist
->total_active
--;
440 thread_list_add (&m
->unuse
, thread
);
443 /* Free all unused thread. */
445 thread_list_free (struct thread_master
*m
, struct thread_list
*list
)
450 for (t
= list
->head
; t
; t
= next
)
453 XFREE (MTYPE_THREAD
, t
);
460 thread_array_free (struct thread_master
*m
, struct thread
**thread_array
)
465 for (index
= 0; index
< m
->fd_limit
; ++index
)
467 t
= thread_array
[index
];
470 thread_array
[index
] = NULL
;
471 XFREE (MTYPE_THREAD
, t
);
475 XFREE (MTYPE_THREAD
, thread_array
);
479 thread_queue_free (struct thread_master
*m
, struct pqueue
*queue
)
483 for (i
= 0; i
< queue
->size
; i
++)
484 XFREE(MTYPE_THREAD
, queue
->array
[i
]);
486 m
->alloc
-= queue
->size
;
487 pqueue_delete(queue
);
491 * thread_master_free_unused
493 * As threads are finished with they are put on the
494 * unuse list for later reuse.
495 * If we are shutting down, Free up unused threads
496 * So we can see if we forget to shut anything off
499 thread_master_free_unused (struct thread_master
*m
)
502 while ((t
= thread_trim_head(&m
->unuse
)) != NULL
)
504 XFREE(MTYPE_THREAD
, t
);
508 /* Stop thread scheduler. */
510 thread_master_free (struct thread_master
*m
)
512 thread_array_free (m
, m
->read
);
513 thread_array_free (m
, m
->write
);
514 thread_queue_free (m
, m
->timer
);
515 thread_list_free (m
, &m
->event
);
516 thread_list_free (m
, &m
->ready
);
517 thread_list_free (m
, &m
->unuse
);
518 thread_queue_free (m
, m
->background
);
520 #if defined(HAVE_POLL)
521 XFREE (MTYPE_THREAD_MASTER
, m
->handler
.pfds
);
523 XFREE (MTYPE_THREAD_MASTER
, m
);
527 hash_clean (cpu_record
, cpu_record_hash_free
);
528 hash_free (cpu_record
);
533 /* Return remain time in second. */
535 thread_timer_remain_second (struct thread
*thread
)
537 int64_t remain
= monotime_until(&thread
->u
.sands
, NULL
) / 1000000LL;
538 return remain
< 0 ? 0 : remain
;
541 #define debugargdef const char *funcname, const char *schedfrom, int fromln
542 #define debugargpass funcname, schedfrom, fromln
545 thread_timer_remain(struct thread
*thread
)
547 struct timeval remain
;
548 monotime_until(&thread
->u
.sands
, &remain
);
552 /* Get new thread. */
553 static struct thread
*
554 thread_get (struct thread_master
*m
, u_char type
,
555 int (*func
) (struct thread
*), void *arg
, debugargdef
)
557 struct thread
*thread
= thread_trim_head (&m
->unuse
);
558 struct cpu_thread_history tmp
;
562 thread
= XCALLOC (MTYPE_THREAD
, sizeof (struct thread
));
566 thread
->add_type
= type
;
570 thread
->yield
= THREAD_YIELD_TIME_SLOT
; /* default */
573 * So if the passed in funcname is not what we have
574 * stored that means the thread->hist needs to be
575 * updated. We keep the last one around in unused
576 * under the assumption that we are probably
577 * going to immediately allocate the same
579 * This hopefully saves us some serious
582 if (thread
->funcname
!= funcname
||
583 thread
->func
!= func
)
586 tmp
.funcname
= funcname
;
587 thread
->hist
= hash_get (cpu_record
, &tmp
,
588 (void * (*) (void *))cpu_record_hash_alloc
);
590 thread
->hist
->total_active
++;
592 thread
->funcname
= funcname
;
593 thread
->schedfrom
= schedfrom
;
594 thread
->schedfrom_line
= fromln
;
599 #if defined (HAVE_POLL)
601 #define fd_copy_fd_set(X) (X)
603 /* generic add thread function */
604 static struct thread
*
605 generic_thread_add(struct thread_master
*m
, int (*func
) (struct thread
*),
606 void *arg
, int fd
, int dir
, debugargdef
)
608 struct thread
*thread
;
613 if (dir
== THREAD_READ
)
615 event
= (POLLIN
| POLLHUP
);
620 event
= (POLLOUT
| POLLHUP
);
624 nfds_t queuepos
= m
->handler
.pfdcount
;
626 for (i
=0; i
<m
->handler
.pfdcount
; i
++)
627 if (m
->handler
.pfds
[i
].fd
== fd
)
633 /* is there enough space for a new fd? */
634 assert (queuepos
< m
->handler
.pfdsize
);
636 thread
= thread_get (m
, type
, func
, arg
, debugargpass
);
637 m
->handler
.pfds
[queuepos
].fd
= fd
;
638 m
->handler
.pfds
[queuepos
].events
|= event
;
639 if (queuepos
== m
->handler
.pfdcount
)
640 m
->handler
.pfdcount
++;
646 #define fd_copy_fd_set(X) (X)
650 fd_select (struct thread_master
*m
, int size
, thread_fd_set
*read
, thread_fd_set
*write
, thread_fd_set
*except
, struct timeval
*timer_wait
)
653 #if defined(HAVE_POLL)
654 /* recalc timeout for poll. Attention NULL pointer is no timeout with
655 select, where with poll no timeount is -1 */
657 if (timer_wait
!= NULL
)
658 timeout
= (timer_wait
->tv_sec
*1000) + (timer_wait
->tv_usec
/1000);
660 num
= poll (m
->handler
.pfds
, m
->handler
.pfdcount
+ m
->handler
.pfdcountsnmp
, timeout
);
662 num
= select (size
, read
, write
, except
, timer_wait
);
669 fd_is_set (struct thread
*thread
, thread_fd_set
*fdset
, int pos
)
671 #if defined(HAVE_POLL)
674 return FD_ISSET (THREAD_FD (thread
), fdset
);
679 fd_clear_read_write (struct thread
*thread
)
681 #if !defined(HAVE_POLL)
682 thread_fd_set
*fdset
= NULL
;
683 int fd
= THREAD_FD (thread
);
685 if (thread
->type
== THREAD_READ
)
686 fdset
= &thread
->master
->handler
.readfd
;
688 fdset
= &thread
->master
->handler
.writefd
;
690 if (!FD_ISSET (fd
, fdset
))
698 /* Add new read thread. */
700 funcname_thread_add_read_write (int dir
, struct thread_master
*m
,
701 int (*func
) (struct thread
*), void *arg
, int fd
,
704 struct thread
*thread
= NULL
;
706 #if !defined(HAVE_POLL)
707 thread_fd_set
*fdset
= NULL
;
708 if (dir
== THREAD_READ
)
709 fdset
= &m
->handler
.readfd
;
711 fdset
= &m
->handler
.writefd
;
714 #if defined (HAVE_POLL)
715 thread
= generic_thread_add(m
, func
, arg
, fd
, dir
, debugargpass
);
720 if (FD_ISSET (fd
, fdset
))
722 zlog (NULL
, LOG_WARNING
, "There is already %s fd [%d]", (dir
= THREAD_READ
) ? "read" : "write", fd
);
727 thread
= thread_get (m
, dir
, func
, arg
, debugargpass
);
731 if (dir
== THREAD_READ
)
732 thread_add_fd (m
->read
, thread
);
734 thread_add_fd (m
->write
, thread
);
739 static struct thread
*
740 funcname_thread_add_timer_timeval (struct thread_master
*m
,
741 int (*func
) (struct thread
*),
744 struct timeval
*time_relative
,
747 struct thread
*thread
;
748 struct pqueue
*queue
;
752 assert (type
== THREAD_TIMER
|| type
== THREAD_BACKGROUND
);
753 assert (time_relative
);
755 queue
= ((type
== THREAD_TIMER
) ? m
->timer
: m
->background
);
756 thread
= thread_get (m
, type
, func
, arg
, debugargpass
);
758 monotime(&thread
->u
.sands
);
759 timeradd(&thread
->u
.sands
, time_relative
, &thread
->u
.sands
);
761 pqueue_enqueue(thread
, queue
);
766 /* Add timer event thread. */
768 funcname_thread_add_timer (struct thread_master
*m
,
769 int (*func
) (struct thread
*),
770 void *arg
, long timer
,
780 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
, arg
,
781 &trel
, debugargpass
);
784 /* Add timer event thread with "millisecond" resolution */
786 funcname_thread_add_timer_msec (struct thread_master
*m
,
787 int (*func
) (struct thread
*),
788 void *arg
, long timer
,
795 trel
.tv_sec
= timer
/ 1000;
796 trel
.tv_usec
= 1000*(timer
% 1000);
798 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
799 arg
, &trel
, debugargpass
);
802 /* Add timer event thread with "millisecond" resolution */
804 funcname_thread_add_timer_tv (struct thread_master
*m
,
805 int (*func
) (struct thread
*),
806 void *arg
, struct timeval
*tv
,
809 return funcname_thread_add_timer_timeval (m
, func
, THREAD_TIMER
,
810 arg
, tv
, debugargpass
);
813 /* Add a background thread, with an optional millisec delay */
815 funcname_thread_add_background (struct thread_master
*m
,
816 int (*func
) (struct thread
*),
817 void *arg
, long delay
,
826 trel
.tv_sec
= delay
/ 1000;
827 trel
.tv_usec
= 1000*(delay
% 1000);
835 return funcname_thread_add_timer_timeval (m
, func
, THREAD_BACKGROUND
,
836 arg
, &trel
, debugargpass
);
839 /* Add simple event thread. */
841 funcname_thread_add_event (struct thread_master
*m
,
842 int (*func
) (struct thread
*), void *arg
, int val
,
845 struct thread
*thread
;
849 thread
= thread_get (m
, THREAD_EVENT
, func
, arg
, debugargpass
);
851 thread_list_add (&m
->event
, thread
);
857 thread_cancel_read_or_write (struct thread
*thread
, short int state
)
859 #if defined(HAVE_POLL)
862 for (i
=0;i
<thread
->master
->handler
.pfdcount
;++i
)
863 if (thread
->master
->handler
.pfds
[i
].fd
== thread
->u
.fd
)
865 thread
->master
->handler
.pfds
[i
].events
&= ~(state
);
867 /* remove thread fds from pfd list */
868 if (thread
->master
->handler
.pfds
[i
].events
== 0)
870 memmove(thread
->master
->handler
.pfds
+i
,
871 thread
->master
->handler
.pfds
+i
+1,
872 (thread
->master
->handler
.pfdsize
-i
-1) * sizeof(struct pollfd
));
873 thread
->master
->handler
.pfdcount
--;
879 fd_clear_read_write (thread
);
882 /* Cancel thread from scheduler. */
884 thread_cancel (struct thread
*thread
)
886 struct thread_list
*list
= NULL
;
887 struct pqueue
*queue
= NULL
;
888 struct thread
**thread_array
= NULL
;
890 switch (thread
->type
)
893 #if defined (HAVE_POLL)
894 thread_cancel_read_or_write (thread
, POLLIN
| POLLHUP
);
896 thread_cancel_read_or_write (thread
, 0);
898 thread_array
= thread
->master
->read
;
901 #if defined (HAVE_POLL)
902 thread_cancel_read_or_write (thread
, POLLOUT
| POLLHUP
);
904 thread_cancel_read_or_write (thread
, 0);
906 thread_array
= thread
->master
->write
;
909 queue
= thread
->master
->timer
;
912 list
= &thread
->master
->event
;
915 list
= &thread
->master
->ready
;
917 case THREAD_BACKGROUND
:
918 queue
= thread
->master
->background
;
927 assert(thread
->index
>= 0);
928 assert(thread
== queue
->array
[thread
->index
]);
929 pqueue_remove_at(thread
->index
, queue
);
933 thread_list_delete (list
, thread
);
935 else if (thread_array
)
937 thread_delete_fd (thread_array
, thread
);
941 assert(!"Thread should be either in queue or list or array!");
944 thread_add_unuse (thread
->master
, thread
);
947 /* Delete all events which has argument value arg. */
949 thread_cancel_event (struct thread_master
*m
, void *arg
)
951 unsigned int ret
= 0;
952 struct thread
*thread
;
954 thread
= m
->event
.head
;
965 thread_list_delete (&m
->event
, t
);
966 thread_add_unuse (m
, t
);
970 /* thread can be on the ready list too */
971 thread
= m
->ready
.head
;
982 thread_list_delete (&m
->ready
, t
);
983 thread_add_unuse (m
, t
);
989 static struct timeval
*
990 thread_timer_wait (struct pqueue
*queue
, struct timeval
*timer_val
)
994 struct thread
*next_timer
= queue
->array
[0];
995 monotime_until(&next_timer
->u
.sands
, timer_val
);
1001 static struct thread
*
1002 thread_run (struct thread_master
*m
, struct thread
*thread
,
1003 struct thread
*fetch
)
1006 thread_add_unuse (m
, thread
);
1011 thread_process_fds_helper (struct thread_master
*m
, struct thread
*thread
, thread_fd_set
*fdset
, short int state
, int pos
)
1013 struct thread
**thread_array
;
1018 if (thread
->type
== THREAD_READ
)
1019 thread_array
= m
->read
;
1021 thread_array
= m
->write
;
1023 if (fd_is_set (thread
, fdset
, pos
))
1025 fd_clear_read_write (thread
);
1026 thread_delete_fd (thread_array
, thread
);
1027 thread_list_add (&m
->ready
, thread
);
1028 thread
->type
= THREAD_READY
;
1029 #if defined(HAVE_POLL)
1030 thread
->master
->handler
.pfds
[pos
].events
&= ~(state
);
1037 #if defined(HAVE_POLL)
1039 #if defined(HAVE_SNMP)
1040 /* add snmp fds to poll set */
1042 add_snmp_pollfds(struct thread_master
*m
, fd_set
*snmpfds
, int fdsetsize
)
1045 m
->handler
.pfdcountsnmp
= m
->handler
.pfdcount
;
1046 /* cycle trough fds and add neccessary fds to poll set */
1047 for (i
=0;i
<fdsetsize
;++i
)
1049 if (FD_ISSET(i
, snmpfds
))
1051 assert (m
->handler
.pfdcountsnmp
<= m
->handler
.pfdsize
);
1053 m
->handler
.pfds
[m
->handler
.pfdcountsnmp
].fd
= i
;
1054 m
->handler
.pfds
[m
->handler
.pfdcountsnmp
].events
= POLLIN
;
1055 m
->handler
.pfdcountsnmp
++;
1061 /* check poll events */
1063 check_pollfds(struct thread_master
*m
, fd_set
*readfd
, int num
)
1067 for (i
= 0; i
< m
->handler
.pfdcount
&& ready
< num
; ++i
)
1069 /* no event for current fd? immideatly continue */
1070 if(m
->handler
.pfds
[i
].revents
== 0)
1075 /* POLLIN / POLLOUT process event */
1076 if (m
->handler
.pfds
[i
].revents
& POLLIN
)
1077 thread_process_fds_helper(m
, m
->read
[m
->handler
.pfds
[i
].fd
], NULL
, POLLIN
, i
);
1078 if (m
->handler
.pfds
[i
].revents
& POLLOUT
)
1079 thread_process_fds_helper(m
, m
->write
[m
->handler
.pfds
[i
].fd
], NULL
, POLLOUT
, i
);
1081 /* remove fd from list on POLLNVAL */
1082 if (m
->handler
.pfds
[i
].revents
& POLLNVAL
||
1083 m
->handler
.pfds
[i
].revents
& POLLHUP
)
1085 memmove(m
->handler
.pfds
+i
,
1086 m
->handler
.pfds
+i
+1,
1087 (m
->handler
.pfdsize
-i
-1) * sizeof(struct pollfd
));
1088 m
->handler
.pfdcount
--;
1092 m
->handler
.pfds
[i
].revents
= 0;
1098 thread_process_fds (struct thread_master
*m
, thread_fd_set
*rset
, thread_fd_set
*wset
, int num
)
1100 #if defined (HAVE_POLL)
1101 check_pollfds (m
, rset
, num
);
1103 int ready
= 0, index
;
1105 for (index
= 0; index
< m
->fd_limit
&& ready
< num
; ++index
)
1107 ready
+= thread_process_fds_helper (m
, m
->read
[index
], rset
, 0, 0);
1108 ready
+= thread_process_fds_helper (m
, m
->write
[index
], wset
, 0, 0);
1113 /* Add all timers that have popped to the ready list. */
1115 thread_timer_process (struct pqueue
*queue
, struct timeval
*timenow
)
1117 struct thread
*thread
;
1118 unsigned int ready
= 0;
1122 thread
= queue
->array
[0];
1123 if (timercmp (timenow
, &thread
->u
.sands
, <))
1125 pqueue_dequeue(queue
);
1126 thread
->type
= THREAD_READY
;
1127 thread_list_add (&thread
->master
->ready
, thread
);
1133 /* process a list en masse, e.g. for event thread lists */
1135 thread_process (struct thread_list
*list
)
1137 struct thread
*thread
;
1138 struct thread
*next
;
1139 unsigned int ready
= 0;
1141 for (thread
= list
->head
; thread
; thread
= next
)
1143 next
= thread
->next
;
1144 thread_list_delete (list
, thread
);
1145 thread
->type
= THREAD_READY
;
1146 thread_list_add (&thread
->master
->ready
, thread
);
1153 /* Fetch next ready thread. */
1155 thread_fetch (struct thread_master
*m
, struct thread
*fetch
)
1157 struct thread
*thread
;
1158 thread_fd_set readfd
;
1159 thread_fd_set writefd
;
1160 thread_fd_set exceptfd
;
1162 struct timeval timer_val
= { .tv_sec
= 0, .tv_usec
= 0 };
1163 struct timeval timer_val_bg
;
1164 struct timeval
*timer_wait
= &timer_val
;
1165 struct timeval
*timer_wait_bg
;
1171 /* Signals pre-empt everything */
1172 quagga_sigevent_process ();
1174 /* Drain the ready queue of already scheduled jobs, before scheduling
1177 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1178 return thread_run (m
, thread
, fetch
);
1180 /* To be fair to all kinds of threads, and avoid starvation, we
1181 * need to be careful to consider all thread types for scheduling
1182 * in each quanta. I.e. we should not return early from here on.
1185 /* Normal event are the next highest priority. */
1186 thread_process (&m
->event
);
1188 /* Structure copy. */
1189 #if !defined(HAVE_POLL)
1190 readfd
= fd_copy_fd_set(m
->handler
.readfd
);
1191 writefd
= fd_copy_fd_set(m
->handler
.writefd
);
1192 exceptfd
= fd_copy_fd_set(m
->handler
.exceptfd
);
1195 /* Calculate select wait timer if nothing else to do */
1196 if (m
->ready
.count
== 0)
1198 timer_wait
= thread_timer_wait (m
->timer
, &timer_val
);
1199 timer_wait_bg
= thread_timer_wait (m
->background
, &timer_val_bg
);
1201 if (timer_wait_bg
&&
1202 (!timer_wait
|| (timercmp (timer_wait
, timer_wait_bg
, >))))
1203 timer_wait
= timer_wait_bg
;
1206 if (timer_wait
&& timer_wait
->tv_sec
< 0)
1208 timerclear(&timer_val
);
1209 timer_wait
= &timer_val
;
1212 num
= fd_select (m
, FD_SETSIZE
, &readfd
, &writefd
, &exceptfd
, timer_wait
);
1214 /* Signals should get quick treatment */
1218 continue; /* signal received - process it */
1219 zlog_warn ("select() error: %s", safe_strerror (errno
));
1223 /* Check foreground timers. Historically, they have had higher
1224 priority than I/O threads, so let's push them onto the ready
1225 list in front of the I/O threads. */
1227 thread_timer_process (m
->timer
, &now
);
1229 /* Got IO, process it */
1231 thread_process_fds (m
, &readfd
, &writefd
, num
);
1234 /* If any threads were made ready above (I/O or foreground timer),
1235 perhaps we should avoid adding background timers to the ready
1236 list at this time. If this is code is uncommented, then background
1237 timer threads will not run unless there is nothing else to do. */
1238 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1239 return thread_run (m
, thread
, fetch
);
1242 /* Background timer/events, lowest priority */
1243 thread_timer_process (m
->background
, &now
);
1245 if ((thread
= thread_trim_head (&m
->ready
)) != NULL
)
1246 return thread_run (m
, thread
, fetch
);
1251 thread_consumed_time (RUSAGE_T
*now
, RUSAGE_T
*start
, unsigned long *cputime
)
1253 /* This is 'user + sys' time. */
1254 *cputime
= timeval_elapsed (now
->cpu
.ru_utime
, start
->cpu
.ru_utime
) +
1255 timeval_elapsed (now
->cpu
.ru_stime
, start
->cpu
.ru_stime
);
1256 return timeval_elapsed (now
->real
, start
->real
);
1259 /* We should aim to yield after yield milliseconds, which defaults
1260 to THREAD_YIELD_TIME_SLOT .
1261 Note: we are using real (wall clock) time for this calculation.
1262 It could be argued that CPU time may make more sense in certain
1263 contexts. The things to consider are whether the thread may have
1264 blocked (in which case wall time increases, but CPU time does not),
1265 or whether the system is heavily loaded with other processes competing
1266 for CPU time. On balance, wall clock time seems to make sense.
1267 Plus it has the added benefit that gettimeofday should be faster
1268 than calling getrusage. */
1270 thread_should_yield (struct thread
*thread
)
1272 return monotime_since(&thread
->real
, NULL
) > (int64_t)thread
->yield
;
1276 thread_set_yield_time (struct thread
*thread
, unsigned long yield_time
)
1278 thread
->yield
= yield_time
;
1282 thread_getrusage (RUSAGE_T
*r
)
1285 getrusage(RUSAGE_SELF
, &(r
->cpu
));
1288 struct thread
*thread_current
= NULL
;
1290 /* We check thread consumed time. If the system has getrusage, we'll
1291 use that to get in-depth stats on the performance of the thread in addition
1292 to wall clock time stats from gettimeofday. */
1294 thread_call (struct thread
*thread
)
1296 unsigned long realtime
, cputime
;
1297 RUSAGE_T before
, after
;
1299 GETRUSAGE (&before
);
1300 thread
->real
= before
.real
;
1302 thread_current
= thread
;
1303 (*thread
->func
) (thread
);
1304 thread_current
= NULL
;
1308 realtime
= thread_consumed_time (&after
, &before
, &cputime
);
1309 thread
->hist
->real
.total
+= realtime
;
1310 if (thread
->hist
->real
.max
< realtime
)
1311 thread
->hist
->real
.max
= realtime
;
1312 thread
->hist
->cpu
.total
+= cputime
;
1313 if (thread
->hist
->cpu
.max
< cputime
)
1314 thread
->hist
->cpu
.max
= cputime
;
1316 ++(thread
->hist
->total_calls
);
1317 thread
->hist
->types
|= (1 << thread
->add_type
);
1319 #ifdef CONSUMED_TIME_CHECK
1320 if (realtime
> CONSUMED_TIME_CHECK
)
1323 * We have a CPU Hog on our hands.
1324 * Whinge about it now, so we're aware this is yet another task
1327 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1329 (unsigned long) thread
->func
,
1330 realtime
/1000, cputime
/1000);
1332 #endif /* CONSUMED_TIME_CHECK */
1335 /* Execute thread */
1337 funcname_thread_execute (struct thread_master
*m
,
1338 int (*func
)(struct thread
*),
1343 struct cpu_thread_history tmp
;
1344 struct thread dummy
;
1346 memset (&dummy
, 0, sizeof (struct thread
));
1348 dummy
.type
= THREAD_EVENT
;
1349 dummy
.add_type
= THREAD_EXECUTE
;
1350 dummy
.master
= NULL
;
1354 tmp
.func
= dummy
.func
= func
;
1355 tmp
.funcname
= dummy
.funcname
= funcname
;
1356 dummy
.hist
= hash_get (cpu_record
, &tmp
,
1357 (void * (*) (void *))cpu_record_hash_alloc
);
1359 dummy
.schedfrom
= schedfrom
;
1360 dummy
.schedfrom_line
= fromln
;
1362 thread_call (&dummy
);