version 1.1.1.2, 2012/10/09 09:22:28
|
version 1.1.1.3, 2013/07/21 23:54:39
|
Line 29
|
Line 29
|
#include "hash.h" |
#include "hash.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; |
Line 93 timeval_elapsed (struct timeval a, struct timeval b)
|
Line 108 timeval_elapsed (struct timeval a, struct timeval b)
|
+ (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 127 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 167 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 235 cpu_record_hash_alloc (struct cpu_thread_history *a)
|
Line 266 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); | strcpy(new->funcname, a->funcname); |
return new; |
return new; |
} |
} |
|
|
Line 244 cpu_record_hash_free (void *a)
|
Line 275 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); |
} |
} |
|
|
Line 303 cpu_record_print(struct vty *vty, thread_type filter)
|
Line 333 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"; | strcpy(tmp.funcname, "TOTAL"); |
tmp.types = filter; |
tmp.types = filter; |
|
|
#ifdef HAVE_RUSAGE |
#ifdef HAVE_RUSAGE |
Line 577 thread_list_free (struct thread_master *m, struct thre
|
Line 607 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--; |
Line 636 thread_timer_remain_second (struct thread *thread)
|
Line 664 thread_timer_remain_second (struct thread *thread)
|
} |
} |
|
|
/* Trim blankspace and "()"s */ |
/* Trim blankspace and "()"s */ |
static char * | void |
strip_funcname (const char *funcname) | strip_funcname (char *dest, const char *funcname) |
{ |
{ |
char buff[100]; | char buff[FUNCNAME_LEN]; |
char tmp, *ret, *e, *b = buff; | char tmp, *e, *b = buff; |
|
|
strncpy(buff, funcname, sizeof(buff)); |
strncpy(buff, funcname, sizeof(buff)); |
buff[ sizeof(buff) -1] = '\0'; |
buff[ sizeof(buff) -1] = '\0'; |
Line 656 strip_funcname (const char *funcname)
|
Line 684 strip_funcname (const char *funcname)
|
|
|
tmp = *e; |
tmp = *e; |
*e = '\0'; |
*e = '\0'; |
ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b); | strcpy (dest, b); |
*e = tmp; |
*e = tmp; |
|
|
return ret; |
|
} |
} |
|
|
/* Get new thread. */ |
/* Get new thread. */ |
Line 667 static struct thread *
|
Line 693 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, const char* funcname) |
{ |
{ |
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 686 thread_get (struct thread_master *m, u_char type,
|
Line 706 thread_get (struct thread_master *m, u_char type,
|
thread->func = func; |
thread->func = func; |
thread->arg = arg; |
thread->arg = arg; |
|
|
thread->funcname = strip_funcname(funcname); | strip_funcname (thread->funcname, funcname); |
|
|
return thread; |
return thread; |
} |
} |
Line 916 thread_cancel_event (struct thread_master *m, void *ar
|
Line 936 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; |
} |
} |
|
|
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 1024 thread_fetch (struct thread_master *m, struct thread *
|
Line 1061 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 1059 thread_fetch (struct thread_master *m, struct thread *
|
Line 1101 thread_fetch (struct thread_master *m, struct thread *
|
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 1070 thread_fetch (struct thread_master *m, struct thread *
|
Line 1132 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. */ |
Line 1128 int
|
Line 1204 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 1157 void
|
Line 1233 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 1170 thread_call (struct thread *thread)
|
Line 1246 thread_call (struct thread *thread)
|
struct cpu_thread_history tmp; |
struct cpu_thread_history tmp; |
|
|
tmp.func = thread->func; |
tmp.func = thread->func; |
tmp.funcname = thread->funcname; | strcpy(tmp.funcname, thread->funcname); |
|
|
thread->hist = hash_get (cpu_record, &tmp, |
thread->hist = hash_get (cpu_record, &tmp, |
(void * (*) (void *))cpu_record_hash_alloc); |
(void * (*) (void *))cpu_record_hash_alloc); |
} |
} |
|
|
GETRUSAGE (&thread->ru); | GETRUSAGE (&before); |
| thread->real = before.real; |
|
|
(*thread->func) (thread); |
(*thread->func) (thread); |
|
|
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 1209 thread_call (struct thread *thread)
|
Line 1286 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 1231 funcname_thread_execute (struct thread_master *m,
|
Line 1306 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); | strip_funcname (dummy.funcname, funcname); |
thread_call (&dummy); |
thread_call (&dummy); |
|
|
XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname); |
|
|
|
return NULL; |
return NULL; |
} |
} |