version 1.1, 2012/02/21 17:26:12
|
version 1.1.1.4, 2016/11/02 10:09:11
|
Line 27
|
Line 27
|
#include "memory.h" |
#include "memory.h" |
#include "log.h" |
#include "log.h" |
#include "hash.h" |
#include "hash.h" |
|
#include "pqueue.h" |
#include "command.h" |
#include "command.h" |
#include "sigevent.h" |
#include "sigevent.h" |
| |
| #if defined HAVE_SNMP && defined SNMP_AGENTX |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include <net-snmp/agent/snmp_vars.h> |
| |
| extern int agentx_enabled; |
| #endif |
| |
| #if defined(__APPLE__) |
| #include <mach/mach.h> |
| #include <mach/mach_time.h> |
| #endif |
| |
| |
/* Recent absolute time of day */ |
/* Recent absolute time of day */ |
struct timeval recent_time; |
struct timeval recent_time; |
static struct timeval last_recent_time; |
static struct timeval last_recent_time; |
Line 38 static struct timeval relative_time;
|
Line 54 static struct timeval relative_time;
|
static struct timeval relative_time_base; |
static struct timeval relative_time_base; |
/* init flag */ |
/* init flag */ |
static unsigned short timers_inited; |
static unsigned short timers_inited; |
| |
static struct hash *cpu_record = NULL; |
static struct hash *cpu_record = NULL; |
| |
/* Struct timeval's tv_usec one second value. */ |
/* Struct timeval's tv_usec one second value. */ |
#define TIMER_SECOND_MICRO 1000000L |
#define TIMER_SECOND_MICRO 1000000L |
|
|
Line 86 timeval_cmp (struct timeval a, struct timeval b)
|
Line 102 timeval_cmp (struct timeval a, struct timeval b)
|
? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); |
? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); |
} |
} |
|
|
static unsigned long | unsigned long |
timeval_elapsed (struct timeval a, struct timeval b) |
timeval_elapsed (struct timeval a, struct timeval b) |
{ |
{ |
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) |
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) |
+ (a.tv_usec - b.tv_usec)); |
+ (a.tv_usec - b.tv_usec)); |
} |
} |
| |
#ifndef HAVE_CLOCK_MONOTONIC | #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) |
static void |
static void |
quagga_gettimeofday_relative_adjust (void) |
quagga_gettimeofday_relative_adjust (void) |
{ |
{ |
Line 112 quagga_gettimeofday_relative_adjust (void)
|
Line 128 quagga_gettimeofday_relative_adjust (void)
|
} |
} |
last_recent_time = recent_time; |
last_recent_time = recent_time; |
} |
} |
#endif /* !HAVE_CLOCK_MONOTONIC */ | #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ |
|
|
/* gettimeofday wrapper, to keep recent_time updated */ |
/* gettimeofday wrapper, to keep recent_time updated */ |
static int |
static int |
Line 152 quagga_get_relative (struct timeval *tv)
|
Line 168 quagga_get_relative (struct timeval *tv)
|
relative_time.tv_usec = tp.tv_nsec / 1000; |
relative_time.tv_usec = tp.tv_nsec / 1000; |
} |
} |
} |
} |
#else /* !HAVE_CLOCK_MONOTONIC */ | #elif defined(__APPLE__) |
| { |
| uint64_t ticks; |
| uint64_t useconds; |
| static mach_timebase_info_data_t timebase_info; |
| |
| ticks = mach_absolute_time(); |
| if (timebase_info.denom == 0) |
| mach_timebase_info(&timebase_info); |
| |
| useconds = ticks * timebase_info.numer / timebase_info.denom / 1000; |
| relative_time.tv_sec = useconds / 1000000; |
| relative_time.tv_usec = useconds % 1000000; |
| |
| return 0; |
| } |
| #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ |
if (!(ret = quagga_gettimeofday (&recent_time))) |
if (!(ret = quagga_gettimeofday (&recent_time))) |
quagga_gettimeofday_relative_adjust(); |
quagga_gettimeofday_relative_adjust(); |
#endif /* HAVE_CLOCK_MONOTONIC */ |
#endif /* HAVE_CLOCK_MONOTONIC */ |
Line 215 recent_relative_time (void)
|
Line 247 recent_relative_time (void)
|
{ |
{ |
return relative_time; |
return relative_time; |
} |
} |
| |
static unsigned int |
static unsigned int |
cpu_record_hash_key (struct cpu_thread_history *a) |
cpu_record_hash_key (struct cpu_thread_history *a) |
{ |
{ |
Line 235 cpu_record_hash_alloc (struct cpu_thread_history *a)
|
Line 267 cpu_record_hash_alloc (struct cpu_thread_history *a)
|
struct cpu_thread_history *new; |
struct cpu_thread_history *new; |
new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history)); |
new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history)); |
new->func = a->func; |
new->func = a->func; |
new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname); | new->funcname = a->funcname; |
return new; |
return new; |
} |
} |
|
|
Line 244 cpu_record_hash_free (void *a)
|
Line 276 cpu_record_hash_free (void *a)
|
{ |
{ |
struct cpu_thread_history *hist = a; |
struct cpu_thread_history *hist = a; |
|
|
XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname); |
|
XFREE (MTYPE_THREAD_STATS, hist); |
XFREE (MTYPE_THREAD_STATS, hist); |
} |
} |
|
|
static inline void | static void |
vty_out_cpu_thread_history(struct vty* vty, |
vty_out_cpu_thread_history(struct vty* vty, |
struct cpu_thread_history *a) |
struct cpu_thread_history *a) |
{ |
{ |
Line 303 cpu_record_print(struct vty *vty, thread_type filter)
|
Line 334 cpu_record_print(struct vty *vty, thread_type filter)
|
void *args[3] = {&tmp, vty, &filter}; |
void *args[3] = {&tmp, vty, &filter}; |
|
|
memset(&tmp, 0, sizeof tmp); |
memset(&tmp, 0, sizeof tmp); |
tmp.funcname = (char *)"TOTAL"; | tmp.funcname = "TOTAL"; |
tmp.types = filter; |
tmp.types = filter; |
|
|
#ifdef HAVE_RUSAGE |
#ifdef HAVE_RUSAGE |
Line 465 DEFUN(clear_thread_cpu,
|
Line 496 DEFUN(clear_thread_cpu,
|
cpu_record_clear (filter); |
cpu_record_clear (filter); |
return CMD_SUCCESS; |
return CMD_SUCCESS; |
} |
} |
| |
/* List allocation and head/tail print out. */ | static int |
static void | thread_timer_cmp(void *a, void *b) |
thread_list_debug (struct thread_list *list) | |
{ |
{ |
printf ("count [%d] head [%p] tail [%p]\n", | struct thread *thread_a = a; |
list->count, list->head, list->tail); | struct thread *thread_b = b; |
| |
| long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands); |
| |
| if (cmp < 0) |
| return -1; |
| if (cmp > 0) |
| return 1; |
| return 0; |
} |
} |
|
|
/* Debug print for thread_master. */ | static void |
static void __attribute__ ((unused)) | thread_timer_update(void *node, int actual_position) |
thread_master_debug (struct thread_master *m) | |
{ |
{ |
printf ("-----------\n"); | struct thread *thread = node; |
printf ("readlist : "); | |
thread_list_debug (&m->read); | thread->index = actual_position; |
printf ("writelist : "); | |
thread_list_debug (&m->write); | |
printf ("timerlist : "); | |
thread_list_debug (&m->timer); | |
printf ("eventlist : "); | |
thread_list_debug (&m->event); | |
printf ("unuselist : "); | |
thread_list_debug (&m->unuse); | |
printf ("bgndlist : "); | |
thread_list_debug (&m->background); | |
printf ("total alloc: [%ld]\n", m->alloc); | |
printf ("-----------\n"); | |
} |
} |
| |
/* Allocate new thread master. */ |
/* Allocate new thread master. */ |
struct thread_master * |
struct thread_master * |
thread_master_create () |
thread_master_create () |
{ |
{ |
|
struct thread_master *rv; |
|
|
if (cpu_record == NULL) |
if (cpu_record == NULL) |
cpu_record |
cpu_record |
= hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key, | = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, |
(int (*) (const void *, const void *))cpu_record_hash_cmp); | (int (*) (const void *, const void *))cpu_record_hash_cmp); |
| |
return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, | rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); |
sizeof (struct thread_master)); | |
| /* Initialize the timer queues */ |
| rv->timer = pqueue_create(); |
| rv->background = pqueue_create(); |
| rv->timer->cmp = rv->background->cmp = thread_timer_cmp; |
| rv->timer->update = rv->background->update = thread_timer_update; |
| |
| return rv; |
} |
} |
|
|
/* Add a new thread to the list. */ |
/* Add a new thread to the list. */ |
Line 522 thread_list_add (struct thread_list *list, struct thre
|
Line 556 thread_list_add (struct thread_list *list, struct thre
|
list->count++; |
list->count++; |
} |
} |
|
|
/* Add a new thread just before the point. */ |
|
static void |
|
thread_list_add_before (struct thread_list *list, |
|
struct thread *point, |
|
struct thread *thread) |
|
{ |
|
thread->next = point; |
|
thread->prev = point->prev; |
|
if (point->prev) |
|
point->prev->next = thread; |
|
else |
|
list->head = thread; |
|
point->prev = thread; |
|
list->count++; |
|
} |
|
|
|
/* Delete a thread from the list. */ |
/* Delete a thread from the list. */ |
static struct thread * |
static struct thread * |
thread_list_delete (struct thread_list *list, struct thread *thread) |
thread_list_delete (struct thread_list *list, struct thread *thread) |
Line 564 thread_add_unuse (struct thread_master *m, struct thre
|
Line 582 thread_add_unuse (struct thread_master *m, struct thre
|
assert (thread->prev == NULL); |
assert (thread->prev == NULL); |
assert (thread->type == THREAD_UNUSED); |
assert (thread->type == THREAD_UNUSED); |
thread_list_add (&m->unuse, thread); |
thread_list_add (&m->unuse, thread); |
/* XXX: Should we deallocate funcname here? */ |
|
} |
} |
|
|
/* Free all unused thread. */ |
/* Free all unused thread. */ |
Line 577 thread_list_free (struct thread_master *m, struct thre
|
Line 594 thread_list_free (struct thread_master *m, struct thre
|
for (t = list->head; t; t = next) |
for (t = list->head; t; t = next) |
{ |
{ |
next = t->next; |
next = t->next; |
if (t->funcname) |
|
XFREE (MTYPE_THREAD_FUNCNAME, t->funcname); |
|
XFREE (MTYPE_THREAD, t); |
XFREE (MTYPE_THREAD, t); |
list->count--; |
list->count--; |
m->alloc--; |
m->alloc--; |
} |
} |
} |
} |
|
|
|
static void |
|
thread_queue_free (struct thread_master *m, struct pqueue *queue) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < queue->size; i++) |
|
XFREE(MTYPE_THREAD, queue->array[i]); |
|
|
|
m->alloc -= queue->size; |
|
pqueue_delete(queue); |
|
} |
|
|
/* Stop thread scheduler. */ |
/* Stop thread scheduler. */ |
void |
void |
thread_master_free (struct thread_master *m) |
thread_master_free (struct thread_master *m) |
{ |
{ |
thread_list_free (m, &m->read); |
thread_list_free (m, &m->read); |
thread_list_free (m, &m->write); |
thread_list_free (m, &m->write); |
thread_list_free (m, &m->timer); | thread_queue_free (m, m->timer); |
thread_list_free (m, &m->event); |
thread_list_free (m, &m->event); |
thread_list_free (m, &m->ready); |
thread_list_free (m, &m->ready); |
thread_list_free (m, &m->unuse); |
thread_list_free (m, &m->unuse); |
thread_list_free (m, &m->background); | thread_queue_free (m, m->background); |
|
|
XFREE (MTYPE_THREAD_MASTER, m); |
XFREE (MTYPE_THREAD_MASTER, m); |
|
|
Line 608 thread_master_free (struct thread_master *m)
|
Line 635 thread_master_free (struct thread_master *m)
|
} |
} |
|
|
/* Thread list is empty or not. */ |
/* Thread list is empty or not. */ |
static inline int | static int |
thread_empty (struct thread_list *list) |
thread_empty (struct thread_list *list) |
{ |
{ |
return list->head ? 0 : 1; |
return list->head ? 0 : 1; |
Line 635 thread_timer_remain_second (struct thread *thread)
|
Line 662 thread_timer_remain_second (struct thread *thread)
|
return 0; |
return 0; |
} |
} |
|
|
/* Trim blankspace and "()"s */ | struct timeval |
static char * | thread_timer_remain(struct thread *thread) |
strip_funcname (const char *funcname) | |
{ |
{ |
char buff[100]; | quagga_get_relative(NULL); |
char tmp, *ret, *e, *b = buff; | |
|
|
strncpy(buff, funcname, sizeof(buff)); | return timeval_subtract(thread->u.sands, relative_time); |
buff[ sizeof(buff) -1] = '\0'; | |
e = buff +strlen(buff) -1; | |
| |
/* Wont work for funcname == "Word (explanation)" */ | |
| |
while (*b == ' ' || *b == '(') | |
++b; | |
while (*e == ' ' || *e == ')') | |
--e; | |
e++; | |
| |
tmp = *e; | |
*e = '\0'; | |
ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b); | |
*e = tmp; | |
| |
return ret; | |
} |
} |
|
|
|
#define debugargdef const char *funcname, const char *schedfrom, int fromln |
|
#define debugargpass funcname, schedfrom, fromln |
|
|
/* Get new thread. */ |
/* Get new thread. */ |
static struct thread * |
static struct thread * |
thread_get (struct thread_master *m, u_char type, |
thread_get (struct thread_master *m, u_char type, |
int (*func) (struct thread *), void *arg, const char* funcname) | int (*func) (struct thread *), void *arg, debugargdef) |
{ |
{ |
struct thread *thread; | struct thread *thread = thread_trim_head (&m->unuse); |
|
|
if (!thread_empty (&m->unuse)) | if (! thread) |
{ |
{ |
thread = thread_trim_head (&m->unuse); |
|
if (thread->funcname) |
|
XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname); |
|
} |
|
else |
|
{ |
|
thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); |
thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); |
m->alloc++; |
m->alloc++; |
} |
} |
Line 685 thread_get (struct thread_master *m, u_char type,
|
Line 690 thread_get (struct thread_master *m, u_char type,
|
thread->master = m; |
thread->master = m; |
thread->func = func; |
thread->func = func; |
thread->arg = arg; |
thread->arg = arg; |
| thread->index = -1; |
thread->funcname = strip_funcname(funcname); | |
|
|
|
thread->funcname = funcname; |
|
thread->schedfrom = schedfrom; |
|
thread->schedfrom_line = fromln; |
|
|
return thread; |
return thread; |
} |
} |
|
|
/* Add new read thread. */ |
/* Add new read thread. */ |
struct thread * |
struct thread * |
funcname_thread_add_read (struct thread_master *m, |
funcname_thread_add_read (struct thread_master *m, |
int (*func) (struct thread *), void *arg, int fd, const char* funcname) | int (*func) (struct thread *), void *arg, int fd, |
| debugargdef) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
|
|
Line 706 funcname_thread_add_read (struct thread_master *m,
|
Line 715 funcname_thread_add_read (struct thread_master *m,
|
return NULL; |
return NULL; |
} |
} |
|
|
thread = thread_get (m, THREAD_READ, func, arg, funcname); | thread = thread_get (m, THREAD_READ, func, arg, debugargpass); |
FD_SET (fd, &m->readfd); |
FD_SET (fd, &m->readfd); |
thread->u.fd = fd; |
thread->u.fd = fd; |
thread_list_add (&m->read, thread); |
thread_list_add (&m->read, thread); |
Line 717 funcname_thread_add_read (struct thread_master *m,
|
Line 726 funcname_thread_add_read (struct thread_master *m,
|
/* Add new write thread. */ |
/* Add new write thread. */ |
struct thread * |
struct thread * |
funcname_thread_add_write (struct thread_master *m, |
funcname_thread_add_write (struct thread_master *m, |
int (*func) (struct thread *), void *arg, int fd, const char* funcname) | int (*func) (struct thread *), void *arg, int fd, |
| debugargdef) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
|
|
Line 729 funcname_thread_add_write (struct thread_master *m,
|
Line 739 funcname_thread_add_write (struct thread_master *m,
|
return NULL; |
return NULL; |
} |
} |
|
|
thread = thread_get (m, THREAD_WRITE, func, arg, funcname); | thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); |
FD_SET (fd, &m->writefd); |
FD_SET (fd, &m->writefd); |
thread->u.fd = fd; |
thread->u.fd = fd; |
thread_list_add (&m->write, thread); |
thread_list_add (&m->write, thread); |
Line 742 funcname_thread_add_timer_timeval (struct thread_maste
|
Line 752 funcname_thread_add_timer_timeval (struct thread_maste
|
int (*func) (struct thread *), |
int (*func) (struct thread *), |
int type, |
int type, |
void *arg, |
void *arg, |
struct timeval *time_relative, | struct timeval *time_relative, |
const char* funcname) | debugargdef) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
struct thread_list *list; | struct pqueue *queue; |
struct timeval alarm_time; |
struct timeval alarm_time; |
struct thread *tt; |
|
|
|
assert (m != NULL); |
assert (m != NULL); |
|
|
assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); |
assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); |
assert (time_relative); |
assert (time_relative); |
|
|
list = ((type == THREAD_TIMER) ? &m->timer : &m->background); | queue = ((type == THREAD_TIMER) ? m->timer : m->background); |
thread = thread_get (m, type, func, arg, funcname); | thread = thread_get (m, type, func, arg, debugargpass); |
|
|
/* Do we need jitter here? */ |
/* Do we need jitter here? */ |
quagga_get_relative (NULL); |
quagga_get_relative (NULL); |
Line 764 funcname_thread_add_timer_timeval (struct thread_maste
|
Line 773 funcname_thread_add_timer_timeval (struct thread_maste
|
alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec; |
alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec; |
thread->u.sands = timeval_adjust(alarm_time); |
thread->u.sands = timeval_adjust(alarm_time); |
|
|
/* Sort by timeval. */ | pqueue_enqueue(thread, queue); |
for (tt = list->head; tt; tt = tt->next) | |
if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) | |
break; | |
| |
if (tt) | |
thread_list_add_before (list, tt, thread); | |
else | |
thread_list_add (list, thread); | |
| |
return thread; |
return thread; |
} |
} |
|
|
Line 782 funcname_thread_add_timer_timeval (struct thread_maste
|
Line 782 funcname_thread_add_timer_timeval (struct thread_maste
|
struct thread * |
struct thread * |
funcname_thread_add_timer (struct thread_master *m, |
funcname_thread_add_timer (struct thread_master *m, |
int (*func) (struct thread *), |
int (*func) (struct thread *), |
void *arg, long timer, const char* funcname) | void *arg, long timer, |
| debugargdef) |
{ |
{ |
struct timeval trel; |
struct timeval trel; |
|
|
Line 792 funcname_thread_add_timer (struct thread_master *m,
|
Line 793 funcname_thread_add_timer (struct thread_master *m,
|
trel.tv_usec = 0; |
trel.tv_usec = 0; |
|
|
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, |
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, |
&trel, funcname); | &trel, debugargpass); |
} |
} |
|
|
/* Add timer event thread with "millisecond" resolution */ |
/* Add timer event thread with "millisecond" resolution */ |
struct thread * |
struct thread * |
funcname_thread_add_timer_msec (struct thread_master *m, |
funcname_thread_add_timer_msec (struct thread_master *m, |
int (*func) (struct thread *), |
int (*func) (struct thread *), |
void *arg, long timer, const char* funcname) | void *arg, long timer, |
| debugargdef) |
{ |
{ |
struct timeval trel; |
struct timeval trel; |
|
|
Line 809 funcname_thread_add_timer_msec (struct thread_master *
|
Line 811 funcname_thread_add_timer_msec (struct thread_master *
|
trel.tv_usec = 1000*(timer % 1000); |
trel.tv_usec = 1000*(timer % 1000); |
|
|
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, |
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, |
arg, &trel, funcname); | arg, &trel, debugargpass); |
} |
} |
|
|
/* Add a background thread, with an optional millisec delay */ |
/* Add a background thread, with an optional millisec delay */ |
struct thread * |
struct thread * |
funcname_thread_add_background (struct thread_master *m, |
funcname_thread_add_background (struct thread_master *m, |
int (*func) (struct thread *), |
int (*func) (struct thread *), |
void *arg, long delay, | void *arg, long delay, |
const char *funcname) | debugargdef) |
{ |
{ |
struct timeval trel; |
struct timeval trel; |
|
|
Line 835 funcname_thread_add_background (struct thread_master *
|
Line 837 funcname_thread_add_background (struct thread_master *
|
} |
} |
|
|
return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND, |
return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND, |
arg, &trel, funcname); | arg, &trel, debugargpass); |
} |
} |
|
|
/* Add simple event thread. */ |
/* Add simple event thread. */ |
struct thread * |
struct thread * |
funcname_thread_add_event (struct thread_master *m, |
funcname_thread_add_event (struct thread_master *m, |
int (*func) (struct thread *), void *arg, int val, const char* funcname) | int (*func) (struct thread *), void *arg, int val, |
| debugargdef) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
|
|
assert (m != NULL); |
assert (m != NULL); |
|
|
thread = thread_get (m, THREAD_EVENT, func, arg, funcname); | thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); |
thread->u.val = val; |
thread->u.val = val; |
thread_list_add (&m->event, thread); |
thread_list_add (&m->event, thread); |
|
|
Line 858 funcname_thread_add_event (struct thread_master *m,
|
Line 861 funcname_thread_add_event (struct thread_master *m,
|
void |
void |
thread_cancel (struct thread *thread) |
thread_cancel (struct thread *thread) |
{ |
{ |
struct thread_list *list; | struct thread_list *list = NULL; |
| struct pqueue *queue = NULL; |
|
|
switch (thread->type) |
switch (thread->type) |
{ |
{ |
Line 873 thread_cancel (struct thread *thread)
|
Line 877 thread_cancel (struct thread *thread)
|
list = &thread->master->write; |
list = &thread->master->write; |
break; |
break; |
case THREAD_TIMER: |
case THREAD_TIMER: |
list = &thread->master->timer; | queue = thread->master->timer; |
break; |
break; |
case THREAD_EVENT: |
case THREAD_EVENT: |
list = &thread->master->event; |
list = &thread->master->event; |
Line 882 thread_cancel (struct thread *thread)
|
Line 886 thread_cancel (struct thread *thread)
|
list = &thread->master->ready; |
list = &thread->master->ready; |
break; |
break; |
case THREAD_BACKGROUND: |
case THREAD_BACKGROUND: |
list = &thread->master->background; | queue = thread->master->background; |
break; |
break; |
default: |
default: |
return; |
return; |
break; |
break; |
} |
} |
thread_list_delete (list, thread); | |
| if (queue) |
| { |
| assert(thread->index >= 0); |
| assert(thread == queue->array[thread->index]); |
| pqueue_remove_at(thread->index, queue); |
| } |
| else if (list) |
| { |
| thread_list_delete (list, thread); |
| } |
| else |
| { |
| assert(!"Thread should be either in queue or list!"); |
| } |
| |
thread->type = THREAD_UNUSED; |
thread->type = THREAD_UNUSED; |
thread_add_unuse (thread->master, thread); |
thread_add_unuse (thread->master, thread); |
} |
} |
Line 916 thread_cancel_event (struct thread_master *m, void *ar
|
Line 935 thread_cancel_event (struct thread_master *m, void *ar
|
thread_add_unuse (m, t); |
thread_add_unuse (m, t); |
} |
} |
} |
} |
|
|
|
/* thread can be on the ready list too */ |
|
thread = m->ready.head; |
|
while (thread) |
|
{ |
|
struct thread *t; |
|
|
|
t = thread; |
|
thread = t->next; |
|
|
|
if (t->arg == arg) |
|
{ |
|
ret++; |
|
thread_list_delete (&m->ready, t); |
|
t->type = THREAD_UNUSED; |
|
thread_add_unuse (m, t); |
|
} |
|
} |
return ret; |
return ret; |
} |
} |
|
|
static struct timeval * |
static struct timeval * |
thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val) | thread_timer_wait (struct pqueue *queue, struct timeval *timer_val) |
{ |
{ |
if (!thread_empty (tlist)) | if (queue->size) |
{ |
{ |
*timer_val = timeval_subtract (tlist->head->u.sands, relative_time); | struct thread *next_timer = queue->array[0]; |
| *timer_val = timeval_subtract (next_timer->u.sands, relative_time); |
return timer_val; |
return timer_val; |
} |
} |
return NULL; |
return NULL; |
Line 936 thread_run (struct thread_master *m, struct thread *th
|
Line 974 thread_run (struct thread_master *m, struct thread *th
|
{ |
{ |
*fetch = *thread; |
*fetch = *thread; |
thread->type = THREAD_UNUSED; |
thread->type = THREAD_UNUSED; |
thread->funcname = NULL; /* thread_call will free fetch's copied pointer */ |
|
thread_add_unuse (m, thread); |
thread_add_unuse (m, thread); |
return fetch; |
return fetch; |
} |
} |
Line 969 thread_process_fd (struct thread_list *list, fd_set *f
|
Line 1006 thread_process_fd (struct thread_list *list, fd_set *f
|
|
|
/* Add all timers that have popped to the ready list. */ |
/* Add all timers that have popped to the ready list. */ |
static unsigned int |
static unsigned int |
thread_timer_process (struct thread_list *list, struct timeval *timenow) | thread_timer_process (struct pqueue *queue, struct timeval *timenow) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
unsigned int ready = 0; |
unsigned int ready = 0; |
|
|
for (thread = list->head; thread; thread = thread->next) | while (queue->size) |
{ |
{ |
|
thread = queue->array[0]; |
if (timeval_cmp (*timenow, thread->u.sands) < 0) |
if (timeval_cmp (*timenow, thread->u.sands) < 0) |
return ready; |
return ready; |
thread_list_delete (list, thread); | pqueue_dequeue(queue); |
thread->type = THREAD_READY; |
thread->type = THREAD_READY; |
thread_list_add (&thread->master->ready, thread); |
thread_list_add (&thread->master->ready, thread); |
ready++; |
ready++; |
Line 991 static unsigned int
|
Line 1029 static unsigned int
|
thread_process (struct thread_list *list) |
thread_process (struct thread_list *list) |
{ |
{ |
struct thread *thread; |
struct thread *thread; |
|
struct thread *next; |
unsigned int ready = 0; |
unsigned int ready = 0; |
|
|
for (thread = list->head; thread; thread = thread->next) | for (thread = list->head; thread; thread = next) |
{ |
{ |
|
next = thread->next; |
thread_list_delete (list, thread); |
thread_list_delete (list, thread); |
thread->type = THREAD_READY; |
thread->type = THREAD_READY; |
thread_list_add (&thread->master->ready, thread); |
thread_list_add (&thread->master->ready, thread); |
Line 1020 thread_fetch (struct thread_master *m, struct thread *
|
Line 1060 thread_fetch (struct thread_master *m, struct thread *
|
while (1) |
while (1) |
{ |
{ |
int num = 0; |
int num = 0; |
|
#if defined HAVE_SNMP && defined SNMP_AGENTX |
|
struct timeval snmp_timer_wait; |
|
int snmpblock = 0; |
|
int fdsetsize; |
|
#endif |
|
|
/* Signals pre-empt everything */ |
/* Signals pre-empt everything */ |
quagga_sigevent_process (); |
quagga_sigevent_process (); |
Line 1047 thread_fetch (struct thread_master *m, struct thread *
|
Line 1092 thread_fetch (struct thread_master *m, struct thread *
|
if (m->ready.count == 0) |
if (m->ready.count == 0) |
{ |
{ |
quagga_get_relative (NULL); |
quagga_get_relative (NULL); |
timer_wait = thread_timer_wait (&m->timer, &timer_val); | timer_wait = thread_timer_wait (m->timer, &timer_val); |
timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg); | timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg); |
|
|
if (timer_wait_bg && |
if (timer_wait_bg && |
(!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) |
(!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) |
timer_wait = timer_wait_bg; |
timer_wait = timer_wait_bg; |
} |
} |
|
|
|
#if defined HAVE_SNMP && defined SNMP_AGENTX |
|
/* When SNMP is enabled, we may have to select() on additional |
|
FD. snmp_select_info() will add them to `readfd'. The trick |
|
with this function is its last argument. We need to set it to |
|
0 if timer_wait is not NULL and we need to use the provided |
|
new timer only if it is still set to 0. */ |
|
if (agentx_enabled) |
|
{ |
|
fdsetsize = FD_SETSIZE; |
|
snmpblock = 1; |
|
if (timer_wait) |
|
{ |
|
snmpblock = 0; |
|
memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); |
|
} |
|
snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); |
|
if (snmpblock == 0) |
|
timer_wait = &snmp_timer_wait; |
|
} |
|
#endif |
num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); |
num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); |
|
|
/* Signals should get quick treatment */ |
/* Signals should get quick treatment */ |
Line 1066 thread_fetch (struct thread_master *m, struct thread *
|
Line 1131 thread_fetch (struct thread_master *m, struct thread *
|
return NULL; |
return NULL; |
} |
} |
|
|
|
#if defined HAVE_SNMP && defined SNMP_AGENTX |
|
if (agentx_enabled) |
|
{ |
|
if (num > 0) |
|
snmp_read(&readfd); |
|
else if (num == 0) |
|
{ |
|
snmp_timeout(); |
|
run_alarms(); |
|
} |
|
netsnmp_check_outstanding_agent_requests(); |
|
} |
|
#endif |
|
|
/* Check foreground timers. Historically, they have had higher |
/* Check foreground timers. Historically, they have had higher |
priority than I/O threads, so let's push them onto the ready |
priority than I/O threads, so let's push them onto the ready |
list in front of the I/O threads. */ |
list in front of the I/O threads. */ |
quagga_get_relative (NULL); |
quagga_get_relative (NULL); |
thread_timer_process (&m->timer, &relative_time); | thread_timer_process (m->timer, &relative_time); |
|
|
/* Got IO, process it */ |
/* Got IO, process it */ |
if (num > 0) |
if (num > 0) |
Line 1091 thread_fetch (struct thread_master *m, struct thread *
|
Line 1170 thread_fetch (struct thread_master *m, struct thread *
|
#endif |
#endif |
|
|
/* Background timer/events, lowest priority */ |
/* Background timer/events, lowest priority */ |
thread_timer_process (&m->background, &relative_time); | thread_timer_process (m->background, &relative_time); |
|
|
if ((thread = thread_trim_head (&m->ready)) != NULL) |
if ((thread = thread_trim_head (&m->ready)) != NULL) |
return thread_run (m, thread, fetch); |
return thread_run (m, thread, fetch); |
Line 1124 int
|
Line 1203 int
|
thread_should_yield (struct thread *thread) |
thread_should_yield (struct thread *thread) |
{ |
{ |
quagga_get_relative (NULL); |
quagga_get_relative (NULL); |
return (timeval_elapsed(relative_time, thread->ru.real) > | return (timeval_elapsed(relative_time, thread->real) > |
THREAD_YIELD_TIME_SLOT); |
THREAD_YIELD_TIME_SLOT); |
} |
} |
|
|
Line 1146 thread_getrusage (RUSAGE_T *r)
|
Line 1225 thread_getrusage (RUSAGE_T *r)
|
#endif /* HAVE_CLOCK_MONOTONIC */ |
#endif /* HAVE_CLOCK_MONOTONIC */ |
} |
} |
|
|
|
struct thread *thread_current = NULL; |
|
|
/* We check thread consumed time. If the system has getrusage, we'll |
/* We check thread consumed time. If the system has getrusage, we'll |
use that to get in-depth stats on the performance of the thread in addition |
use that to get in-depth stats on the performance of the thread in addition |
to wall clock time stats from gettimeofday. */ |
to wall clock time stats from gettimeofday. */ |
Line 1153 void
|
Line 1234 void
|
thread_call (struct thread *thread) |
thread_call (struct thread *thread) |
{ |
{ |
unsigned long realtime, cputime; |
unsigned long realtime, cputime; |
RUSAGE_T ru; | RUSAGE_T before, after; |
|
|
/* Cache a pointer to the relevant cpu history thread, if the thread |
/* Cache a pointer to the relevant cpu history thread, if the thread |
* does not have it yet. |
* does not have it yet. |
Line 1172 thread_call (struct thread *thread)
|
Line 1253 thread_call (struct thread *thread)
|
(void * (*) (void *))cpu_record_hash_alloc); |
(void * (*) (void *))cpu_record_hash_alloc); |
} |
} |
|
|
GETRUSAGE (&thread->ru); | GETRUSAGE (&before); |
| thread->real = before.real; |
|
|
|
thread_current = thread; |
(*thread->func) (thread); |
(*thread->func) (thread); |
|
thread_current = NULL; |
|
|
GETRUSAGE (&ru); | GETRUSAGE (&after); |
|
|
realtime = thread_consumed_time (&ru, &thread->ru, &cputime); | realtime = thread_consumed_time (&after, &before, &cputime); |
thread->hist->real.total += realtime; |
thread->hist->real.total += realtime; |
if (thread->hist->real.max < realtime) |
if (thread->hist->real.max < realtime) |
thread->hist->real.max = realtime; |
thread->hist->real.max = realtime; |
Line 1205 thread_call (struct thread *thread)
|
Line 1289 thread_call (struct thread *thread)
|
realtime/1000, cputime/1000); |
realtime/1000, cputime/1000); |
} |
} |
#endif /* CONSUMED_TIME_CHECK */ |
#endif /* CONSUMED_TIME_CHECK */ |
|
|
XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname); |
|
} |
} |
|
|
/* Execute thread */ |
/* Execute thread */ |
Line 1215 funcname_thread_execute (struct thread_master *m,
|
Line 1297 funcname_thread_execute (struct thread_master *m,
|
int (*func)(struct thread *), |
int (*func)(struct thread *), |
void *arg, |
void *arg, |
int val, |
int val, |
const char* funcname) | debugargdef) |
{ |
{ |
struct thread dummy; |
struct thread dummy; |
|
|
Line 1227 funcname_thread_execute (struct thread_master *m,
|
Line 1309 funcname_thread_execute (struct thread_master *m,
|
dummy.func = func; |
dummy.func = func; |
dummy.arg = arg; |
dummy.arg = arg; |
dummy.u.val = val; |
dummy.u.val = val; |
dummy.funcname = strip_funcname (funcname); |
|
thread_call (&dummy); |
|
|
|
XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname); | dummy.funcname = funcname; |
| dummy.schedfrom = schedfrom; |
| dummy.schedfrom_line = fromln; |
| |
| thread_call (&dummy); |
|
|
return NULL; |
return NULL; |
} |
} |