summaryrefslogtreecommitdiffstats
path: root/lib/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/thread.c')
-rw-r--r--lib/thread.c562
1 files changed, 371 insertions, 191 deletions
diff --git a/lib/thread.c b/lib/thread.c
index f2b873ac..3df9acf7 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -31,6 +31,7 @@
#include "command.h"
#include "sigevent.h"
#include "qpthreads.h"
+#include "qtimers.h"
/* Recent absolute time of day */
struct timeval recent_time;
@@ -47,7 +48,12 @@ static qpt_mutex_t thread_mutex;
#define UNLOCK qpt_mutex_unlock(&thread_mutex);
static struct hash *cpu_record = NULL;
-/* Struct timeval's tv_usec one second value. */
+/* Pointer to qtimer pile to be used, if any */
+static qtimer_pile use_qtimer_pile = NULL ;
+static qtimer spare_qtimers = NULL ;
+static unsigned used_standard_timer = 0 ;
+
+/* Struct timeval's tv_usec one second value. */
#define TIMER_SECOND_MICRO 1000000L
/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
@@ -238,18 +244,51 @@ cpu_record_hash_cmp (const struct cpu_thread_history *a,
static void *
cpu_record_hash_alloc (struct cpu_thread_history *a)
{
- struct cpu_thread_history *new;
+ const char* b ;
+ const char* e ;
+ char* n ;
+ int l ;
+ struct cpu_thread_history *new ;
+
+ /* Establish start and length of name, removing leading/trailing
+ * spaces and any enclosing (...) -- recursively.
+ */
+ b = a->funcname ;
+ e = b + strlen(b) - 1 ;
+
+ while (1)
+ {
+ while (*b == ' ')
+ ++b ; /* strip leading spaces */
+ if (*b == '\0')
+ break ; /* quit if now empty */
+ while (*e == ' ')
+ --e ; /* strip trailing spaces */
+ if ((*b != '(') || (*e != ')'))
+ break ; /* quit if not now (...) */
+ ++b ;
+ --e ; /* discard ( and ) */
+ } ;
+
+ l = (e + 1) - b ; /* length excluding trailing \0 */
+
+ n = XMALLOC(MTYPE_THREAD_FUNCNAME, l + 1) ;
+ memcpy(n, b, l) ;
+ n[l] = '\0' ;
+
+ /* Allocate empty structure and set address and name */
new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
- new->func = a->func;
- new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);
- return new;
+ new->func = a->func;
+ new->funcname = n ;
+
+ return new ;
}
static void
cpu_record_hash_free (void *a)
{
struct cpu_thread_history *hist = a;
- char* funcname = miyagi(hist->funcname) ;
+ void* funcname = miyagi(hist->funcname) ;
XFREE (MTYPE_THREAD_FUNCNAME, funcname);
XFREE (MTYPE_THREAD_STATS, hist);
@@ -497,7 +536,6 @@ thread_add_unuse (struct thread_master *m, struct thread *thread)
assert (thread->prev == NULL);
assert (thread->type == THREAD_UNUSED);
thread_list_add (&m->unuse, thread);
- /* XXX: Should we deallocate funcname here? */
}
/* Free all unused thread. */
@@ -510,8 +548,13 @@ thread_list_free (struct thread_master *m, struct thread_list *list)
for (t = list->head; t; t = next)
{
next = t->next;
- if (t->funcname)
- XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);
+
+ if ( (use_qtimer_pile != NULL)
+ && ( (t->type == THREAD_TIMER || t->type == THREAD_BACKGROUND) )
+ && (t->u.qtr != NULL)
+ )
+ qtimer_free(t->u.qtr) ;
+
XFREE (MTYPE_THREAD, t);
list->count--;
m->alloc--;
@@ -522,6 +565,8 @@ thread_list_free (struct thread_master *m, struct thread_list *list)
void
thread_master_free (struct thread_master *m)
{
+ qtimer qtr ;
+
thread_list_free (m, &m->read);
thread_list_free (m, &m->write);
thread_list_free (m, &m->timer);
@@ -540,6 +585,12 @@ thread_master_free (struct thread_master *m)
cpu_record = NULL;
}
UNLOCK
+
+ while ((qtr = spare_qtimers) != NULL)
+ {
+ spare_qtimers = (void*)(qtr->pile) ;
+ qtimer_free(qtr) ;
+ } ;
}
/* Thread list is empty or not. */
@@ -570,34 +621,26 @@ thread_timer_remain_second (struct thread *thread)
return 0;
}
-/* Trim blankspace and "()"s */
-static char *
-strip_funcname (const char *funcname)
-{
- char buff[100];
- char tmp, *ret, *e, *b = buff;
+/* Get new cpu history */
- strncpy(buff, funcname, sizeof(buff));
- buff[ sizeof(buff) -1] = '\0';
- e = buff +strlen(buff) -1;
+static struct cpu_thread_history*
+thread_get_hist(struct thread* thread, const char* funcname)
+{
+ struct cpu_thread_history tmp ;
+ struct cpu_thread_history* hist ;
- /* Wont work for funcname == "Word (explanation)" */
+ tmp.func = thread->func ;
+ tmp.funcname = funcname ;
- while (*b == ' ' || *b == '(')
- ++b;
- while (*e == ' ' || *e == ')')
- --e;
- e++;
+ LOCK
+ hist = hash_get (cpu_record, &tmp,
+ (void * (*) (void *))cpu_record_hash_alloc);
+ UNLOCK
- tmp = *e;
- *e = '\0';
- ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b);
- *e = tmp;
+ return hist ;
+} ;
- return ret;
-}
-
-/* Get new thread. */
+/* Get new thread. */
static struct thread *
thread_get (struct thread_master *m, u_char type,
int (*func) (struct thread *), void *arg, const char* funcname)
@@ -607,23 +650,22 @@ thread_get (struct thread_master *m, u_char type,
if (!thread_empty (&m->unuse))
{
thread = thread_trim_head (&m->unuse);
- if (thread->funcname)
- XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);
+ memset(thread, 0, sizeof (struct thread)) ;
}
else
{
thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
m->alloc++;
}
- thread->type = type;
+ thread->type = type;
thread->add_type = type;
- thread->master = m;
- thread->func = func;
- thread->arg = arg;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
- thread->funcname = strip_funcname(funcname);
+ thread->hist = thread_get_hist(thread, funcname) ;
- return thread;
+ return thread ;
}
/* Add new read thread. */
@@ -672,48 +714,190 @@ funcname_thread_add_write (struct thread_master *m,
return thread;
}
+/*==============================================================================
+ * Timer Threads -- THREAD_TIMER and THREAD_BACKGROUND
+ *
+ * Standard Timer Threads are sorted by the "struct timeval sands", and
+ * processed by thread_timer_process() -- which moves any expired timer
+ * threads onto the THREAD_READY queue. So, the scheduling of background stuff
+ * is done by not processing the THREAD_BACKGROUND queue until there is
+ * nothing else to do.
+ *
+ * When using a qtimer_pile:
+ *
+ * * THREAD_TIMER threads have an associated qtimer.
+ *
+ * When the timer expires, the qtimer is cut from the thread (and put onto
+ * the spare_qtimers list). The thread is then queued on the THREAD_READY
+ * queue (as before).
+ *
+ * * THREAD_BACKGROUND threads which have a non-zero delay are treated much
+ * as THREAD_TIMER, except that when the timer expires, the thread is
+ * queued on the THREAD_BACKGROUND queue.
+ *
+ * The THREAD_BACKGROUND queue is visited only when there is nothing else
+ * to do.
+ *
+ * Note that when using a qtimer_pile, and there is an active qtimer associated
+ * with the thread, the thread will be on the THREAD_TIMER queue -- so that it
+ * can be collected up and released if required.
+ *
+ * NB: when using a qtimer_pile, if there is a qtimer associated with a
+ * THREAD_TIMER or a THREAD_BACKGROUND thread, then thread->u.qtr points
+ * at the qtimer.
+ *
+ * AND, conversely, if there is no qtimer, then thread->u.ptr == NULL.
+ */
+
+/*------------------------------------------------------------------------------
+ * Set use_qtimer_pile !
+ */
+extern void
+thread_set_qtimer_pile(qtimer_pile pile)
+{
+ passert(!used_standard_timer) ;
+
+ use_qtimer_pile = pile ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Unset qtimer associated with the given THREAD_TIMER or THREAD_BACKGROUND
+ * thread -- if any.
+ *
+ * Moves any qtimer onto the spare_qtimers list.
+ */
+static void
+thread_qtimer_unset(struct thread* thread)
+{
+ qtimer qtr ;
+ assert (thread->type == THREAD_TIMER || thread->type == THREAD_BACKGROUND);
+ assert (use_qtimer_pile != NULL) ;
+
+ qtr = thread->u.qtr ;
+ if (qtr != NULL)
+ {
+ qtimer_unset(qtr) ;
+
+ qtr->pile = (void*)spare_qtimers ;
+ spare_qtimers = qtr ;
+
+ thread->u.qtr = NULL ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The qtimer action function -- when using qtimer pile (!)
+ *
+ * Remove thread from the THREAD_TIMER queue and unset the qtimer, place
+ * thread on the THREAD_READY or the THREAD_BACKGROUND queue as required.
+ */
+static void
+thread_qtimer_dispatch(qtimer qtr, void* timer_info, qtime_mono_t when)
+{
+ struct thread* thread = timer_info ;
+
+ thread_list_delete (&thread->master->timer, thread) ;
+ thread_qtimer_unset(thread) ;
+
+ switch (thread->type)
+ {
+ case THREAD_TIMER:
+ thread->type = THREAD_READY;
+ thread_list_add (&thread->master->ready, thread);
+ break ;
+
+ case THREAD_BACKGROUND:
+ thread_list_add (&thread->master->background, thread);
+ break ;
+
+ default:
+ zabort("invalid thread type in thread_qtimer_dispatch") ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * For standard timers, return time left on first timer on the given list.
+ */
+static struct timeval *
+thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
+{
+ if (!thread_empty (tlist))
+ {
+ *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
+ return timer_val;
+ }
+ return NULL;
+}
+
+/*------------------------------------------------------------------------------
+ * Add timer of given type -- either standard or qtimer_pile as required.
+ *
+ * Timer interval is given as a struct timeval.
+ */
static struct thread *
-funcname_thread_add_timer_timeval (struct thread_master *m,
- int (*func) (struct thread *),
+funcname_thread_add_timer_timeval(struct thread_master *m,
+ int (*func) (struct thread *),
int type,
void *arg,
struct timeval *time_relative,
const char* funcname)
{
struct thread *thread;
- struct thread_list *list;
- struct timeval alarm_time;
- struct thread *tt;
assert (m != NULL);
+ assert (time_relative != NULL);
assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
- assert (time_relative);
- list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
thread = thread_get (m, type, func, arg, funcname);
- /* Do we need jitter here? */
- quagga_get_relative (NULL);
- alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
- alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
- thread->u.sands = timeval_adjust(alarm_time);
-
- /* Sort by timeval. */
- for (tt = list->head; tt; tt = tt->next)
- if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
- break;
+ if (use_qtimer_pile == NULL)
+ {
+ struct thread_list *list;
+ struct timeval alarm_time;
+ struct thread *tt;
- if (tt)
- thread_list_add_before (list, tt, thread);
+ /* Do we need jitter here? */
+ quagga_get_relative (NULL);
+ alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
+ alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
+ thread->u.sands = timeval_adjust(alarm_time);
+
+ /* Sort by timeval. */
+ list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
+ 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);
+
+ used_standard_timer = 1 ;
+ }
else
- thread_list_add (list, thread);
+ {
+ qtimer qtr = spare_qtimers ;
+ if (qtr != NULL)
+ spare_qtimers = (qtimer)(qtr->pile) ;
+
+ qtr = qtimer_init_new(qtr, use_qtimer_pile, NULL, thread) ;
+ thread->u.qtr = qtr ;
+
+ qtimer_set_interval(qtr, timeval2qtime(time_relative),
+ thread_qtimer_dispatch) ;
+ thread_list_add(&m->timer, thread) ;
+ } ;
return thread;
}
-
-/* Add timer event thread. */
+/*------------------------------------------------------------------------------
+ * Add a THREAD_TIMER timer -- either standard or qtimer_pile as required.
+ *
+ * Timer interval is given in seconds.
+ */
struct thread *
funcname_thread_add_timer (struct thread_master *m,
int (*func) (struct thread *),
@@ -721,16 +905,18 @@ funcname_thread_add_timer (struct thread_master *m,
{
struct timeval trel;
- assert (m != NULL);
-
- trel.tv_sec = timer;
+ trel.tv_sec = timer;
trel.tv_usec = 0;
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
&trel, funcname);
}
-/* Add timer event thread with "millisecond" resolution */
+/*------------------------------------------------------------------------------
+ * Add a THREAD_TIMER timer -- either standard or qtimer_pile as required.
+ *
+ * Timer interval is given in milliseconds.
+ */
struct thread *
funcname_thread_add_timer_msec (struct thread_master *m,
int (*func) (struct thread *),
@@ -738,45 +924,56 @@ funcname_thread_add_timer_msec (struct thread_master *m,
{
struct timeval trel;
- assert (m != NULL);
-
- trel.tv_sec = timer / 1000;
- trel.tv_usec = 1000*(timer % 1000);
+ trel.tv_sec = timer / 1000 ;
+ trel.tv_usec = (timer % 1000) * 1000 ;
return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
- arg, &trel, funcname);
+ arg, &trel, funcname);
}
-/* Add a background thread, with an optional millisec delay */
+/*------------------------------------------------------------------------------
+ * Add a THREAD_BACKGROUND thread -- either standard or qtimer_pile as required.
+ *
+ * Timer interval is given in milliseconds.
+ *
+ * For qtimer_pile, if the delay is zero, the thread is placed straight onto
+ * the THREAD_BACKGROUND queue.
+ */
struct thread *
funcname_thread_add_background (struct thread_master *m,
int (*func) (struct thread *),
void *arg, long delay,
const char *funcname)
{
- struct timeval trel;
+ if ((delay != 0) || (use_qtimer_pile == NULL))
+ {
+ struct timeval trel;
- assert (m != NULL);
+ trel.tv_sec = delay / 1000;
+ trel.tv_usec = (delay % 1000) * 1000 ;
- if (delay)
- {
- trel.tv_sec = delay / 1000;
- trel.tv_usec = 1000*(delay % 1000);
+ return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
+ arg, &trel, funcname);
}
else
{
- trel.tv_sec = 0;
- trel.tv_usec = 0;
- }
+ struct thread* thread ;
+
+ assert (m != NULL);
- return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
- arg, &trel, funcname);
+ thread = thread_get (m, THREAD_BACKGROUND, func, arg, funcname);
+ thread_list_add (&m->background, thread) ;
+
+ return thread ;
+ } ;
}
+/*----------------------------------------------------------------------------*/
/* Add simple event thread. */
struct thread *
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,
+ const char* funcname)
{
struct thread *thread;
@@ -789,7 +986,11 @@ funcname_thread_add_event (struct thread_master *m,
return thread;
}
-/* Cancel thread from scheduler. */
+/*------------------------------------------------------------------------------
+ * Cancel thread from scheduler.
+ *
+ * Note that when using qtimer_pile need to unset any associated qtimer.
+ */
void
thread_cancel (struct thread *thread)
{
@@ -808,6 +1009,8 @@ thread_cancel (struct thread *thread)
list = &thread->master->write;
break;
case THREAD_TIMER:
+ if ((use_qtimer_pile != NULL) && (thread->u.qtr != NULL))
+ thread_qtimer_unset(thread) ;
list = &thread->master->timer;
break;
case THREAD_EVENT:
@@ -817,13 +1020,21 @@ thread_cancel (struct thread *thread)
list = &thread->master->ready;
break;
case THREAD_BACKGROUND:
- list = &thread->master->background;
+ if ((use_qtimer_pile != NULL) && (thread->u.qtr != NULL))
+ {
+ thread_qtimer_unset(thread) ;
+ list = &thread->master->timer;
+ }
+ else
+ list = &thread->master->background;
break;
+
default:
- return;
- break;
+ return ;
}
+
thread_list_delete (list, thread);
+
thread->type = THREAD_UNUSED;
thread_add_unuse (thread->master, thread);
}
@@ -854,24 +1065,12 @@ thread_cancel_event (struct thread_master *m, void *arg)
return ret;
}
-static struct timeval *
-thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
-{
- if (!thread_empty (tlist))
- {
- *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
- return timer_val;
- }
- return NULL;
-}
-
static struct thread *
thread_run (struct thread_master *m, struct thread *thread,
struct thread *fetch)
{
*fetch = *thread;
thread->type = THREAD_UNUSED;
- thread->funcname = NULL; /* thread_call will free fetch's copied pointer */
thread_add_unuse (m, thread);
return fetch;
}
@@ -921,7 +1120,11 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow)
return ready;
}
-/* Fetch next ready thread. */
+/*------------------------------------------------------------------------------
+ * Fetch next ready thread -- for standard thread handing.
+ *
+ * (This is not used when using qtimer_pile, or qnexus stuff.)
+ */
struct thread *
thread_fetch (struct thread_master *m, struct thread *fetch)
{
@@ -939,8 +1142,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
int num = 0;
/* Signals are highest priority */
- if (!qpthreads_enabled)
- quagga_sigevent_process ();
+ quagga_sigevent_process ();
/* Normal event are the next highest priority. */
if ((thread = thread_trim_head (&m->event)) != NULL)
@@ -1009,69 +1211,66 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
}
}
-
-/* Fetch next ready thread <= given priority. Events and timeouts only.
- * No I/O. If nothing to do returns NULL and sets event_wait to
- * recommended time to be called again. */
-struct thread *
-thread_fetch_event (enum qpn_priority priority, struct thread_master *m, struct thread *fetch,
- qtime_mono_t *event_wait)
+/*------------------------------------------------------------------------------
+ * Empties the event and ready queues.
+ *
+ * This is used when qnexus is managing most things, including I/O. Must be
+ * using qtimer_pile !
+ *
+ * This runs "legacy" event and ready queues only.
+ *
+ * Returns: the number of threads dispatched.
+ *
+ * Legacy timers are handled by the qtimer_pile, and their related threads will
+ * be placed on the ready queue when they expire.
+ *
+ * The background queue is handled separately.
+ */
+extern int
+thread_dispatch(struct thread_master *m)
{
- struct thread *thread;
- struct timeval timer_val;
- struct timeval timer_val_bg;
- struct timeval *timer_wait;
- struct timeval *timer_wait_bg;
-
- *event_wait = 0;
-
- /* Normal event are the next highest priority. */
- if ((thread = thread_trim_head (&m->event)) != NULL)
- return thread_run (m, thread, fetch);
+ struct thread_list* list ;
+ struct thread fetch ;
+ int count = 0 ;
- if (priority <= qpn_pri_first)
- return NULL;
-
- /* If there are any ready threads from previous scheduler runs,
- * process top of them.
- */
- if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
-
- if (priority <= qpn_pri_second)
- return NULL;
-
- /* Check foreground timers. */
- quagga_get_relative (NULL);
- thread_timer_process (&m->timer, &relative_time);
-
- if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
+ while (1)
+ {
+ if (thread_empty(list = &m->event))
+ if (thread_empty(list = &m->ready))
+ return count ;
- if (priority <= qpn_pri_third)
- return NULL;
+ thread_call(thread_run(m, thread_list_delete(list, list->head), &fetch)) ;
- /* Background timer/events, lowest priority */
- thread_timer_process (&m->background, &relative_time);
+ ++count ;
+ } ;
+} ;
- if ((thread = thread_trim_head (&m->ready)) != NULL)
- return thread_run (m, thread, fetch);
+/*------------------------------------------------------------------------------
+ * Dispatch first item on the background queue, if any.
+ *
+ * This is used when qnexus is managing most things.
+ *
+ * Background threads spend their lives being cycled around the background
+ * queue -- possibly via the timer queue, if a delay is put in before the next
+ * invocation.
+ *
+ * Returns: 1 if dispatched a background thread
+ * 0 if there are no background threads
+ */
+extern int
+thread_dispatch_background(struct thread_master *m)
+{
+ struct thread* thread ;
+ struct thread fetch ;
- /* Calculate select wait timer if nothing else to do */
- timer_wait = thread_timer_wait (&m->timer, &timer_val);
- timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
+ if ((thread = thread_trim_head (&m->background)) == NULL)
+ return 0 ;
- if (timer_wait_bg &&
- (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
- timer_wait = timer_wait_bg;
+ thread_call(thread_run(m, thread, &fetch)) ;
- /* When is the next timer due ? */
- *event_wait = (timer_wait != NULL)
- ? timeval2qtime(timer_wait)
- : 0;
+ return 1 ;
+} ;
- return NULL;
-}
unsigned long
thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
@@ -1130,25 +1329,6 @@ thread_call (struct thread *thread)
unsigned long realtime, cputime;
RUSAGE_T ru;
- /* Cache a pointer to the relevant cpu history thread, if the thread
- * does not have it yet.
- *
- * Callers submitting 'dummy threads' hence must take care that
- * thread->cpu is NULL
- */
- if (!thread->hist)
- {
- struct cpu_thread_history tmp;
-
- tmp.func = thread->func;
- tmp.funcname = thread->funcname;
-
- LOCK
- thread->hist = hash_get (cpu_record, &tmp,
- (void * (*) (void *))cpu_record_hash_alloc);
- UNLOCK
- }
-
GETRUSAGE (&thread->ru);
(*thread->func) (thread);
@@ -1157,19 +1337,22 @@ thread_call (struct thread *thread)
realtime = thread_consumed_time (&ru, &thread->ru, &cputime);
- LOCK
- thread->hist->real.total += realtime;
- if (thread->hist->real.max < realtime)
- thread->hist->real.max = realtime;
+ if (thread->hist != NULL)
+ {
+ LOCK
+ thread->hist->real.total += realtime;
+ if (thread->hist->real.max < realtime)
+ thread->hist->real.max = realtime;
#ifdef HAVE_RUSAGE
- thread->hist->cpu.total += cputime;
- if (thread->hist->cpu.max < cputime)
- thread->hist->cpu.max = cputime;
+ thread->hist->cpu.total += cputime;
+ if (thread->hist->cpu.max < cputime)
+ thread->hist->cpu.max = cputime;
#endif
- ++(thread->hist->total_calls);
- thread->hist->types |= (1 << thread->add_type);
- UNLOCK
+ ++(thread->hist->total_calls);
+ thread->hist->types |= (1 << thread->add_type);
+ UNLOCK
+ } ;
#ifdef CONSUMED_TIME_CHECK
if (realtime > CONSUMED_TIME_CHECK)
@@ -1180,13 +1363,12 @@ thread_call (struct thread *thread)
* to fix.
*/
zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
- thread->funcname,
+ (thread->hist != NULL) ? thread->hist->funcname : "??",
(unsigned long) thread->func,
realtime/1000, cputime/1000);
}
#endif /* CONSUMED_TIME_CHECK */
- XFREE (MTYPE_THREAD_FUNCNAME, thread->funcname);
}
/* Execute thread */
@@ -1207,11 +1389,9 @@ funcname_thread_execute (struct thread_master *m,
dummy.func = func;
dummy.arg = arg;
dummy.u.val = val;
- dummy.funcname = strip_funcname (funcname);
+ dummy.hist = thread_get_hist(&dummy, funcname) ;
thread_call (&dummy);
- XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);
-
return NULL;
}