summaryrefslogtreecommitdiff
path: root/lib/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/thread.c')
-rw-r--r--lib/thread.c180
1 files changed, 98 insertions, 82 deletions
diff --git a/lib/thread.c b/lib/thread.c
index c886058355..5c06c6ddb5 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -58,8 +58,7 @@ static int thread_timer_cmp(const struct thread *a, const struct thread *b)
return 0;
}
-DECLARE_HEAP(thread_timer_list, struct thread, timeritem,
- thread_timer_cmp)
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp)
#if defined(__APPLE__)
#include <mach/mach.h>
@@ -119,7 +118,7 @@ static void vty_out_cpu_thread_history(struct vty *vty,
a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
(a->real.total / a->total_calls), a->real.max);
- vty_out(vty, " %c%c%c%c%c %s\n",
+ vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
@@ -188,7 +187,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
name);
vty_out(vty, "-------------------------------%s\n",
underline);
- vty_out(vty, "%21s %18s %18s\n", "",
+ vty_out(vty, "%30s %18s %18s\n", "",
"CPU (user+system):", "Real (wall-clock):");
vty_out(vty,
"Active Runtime(ms) Invoked Avg uSec Max uSecs");
@@ -211,7 +210,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
vty_out(vty, "\n");
vty_out(vty, "Total thread statistics\n");
vty_out(vty, "-------------------------\n");
- vty_out(vty, "%21s %18s %18s\n", "",
+ vty_out(vty, "%30s %18s %18s\n", "",
"CPU (user+system):", "Real (wall-clock):");
vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
@@ -342,7 +341,7 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
if (!thread)
vty_out(vty, "ERROR ");
else
- vty_out(vty, "%s ", thread->funcname);
+ vty_out(vty, "%s ", thread->xref->funcname);
} else
vty_out(vty, " ");
@@ -352,7 +351,7 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
if (!thread)
vty_out(vty, "ERROR\n");
else
- vty_out(vty, "%s\n", thread->funcname);
+ vty_out(vty, "%s\n", thread->xref->funcname);
} else
vty_out(vty, "\n");
}
@@ -633,9 +632,6 @@ unsigned long thread_timer_remain_second(struct thread *thread)
return thread_timer_remain_msec(thread) / 1000LL;
}
-#define debugargdef const char *funcname, const char *schedfrom, int fromln
-#define debugargpass funcname, schedfrom, fromln
-
struct timeval thread_timer_remain(struct thread *thread)
{
struct timeval remain;
@@ -678,7 +674,7 @@ char *thread_timer_to_hhmmss(char *buf, int buf_size,
/* Get new thread. */
static struct thread *thread_get(struct thread_master *m, uint8_t type,
int (*func)(struct thread *), void *arg,
- debugargdef)
+ const struct xref_threadsched *xref)
{
struct thread *thread = thread_list_pop(&m->unuse);
struct cpu_thread_history tmp;
@@ -707,18 +703,17 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type,
* This hopefully saves us some serious
* hash_get lookups.
*/
- if (thread->funcname != funcname || thread->func != func) {
+ if ((thread->xref && thread->xref->funcname != xref->funcname)
+ || thread->func != func) {
tmp.func = func;
- tmp.funcname = funcname;
+ tmp.funcname = xref->funcname;
thread->hist =
hash_get(m->cpu_record, &tmp,
(void *(*)(void *))cpu_record_hash_alloc);
}
thread->hist->total_active++;
thread->func = func;
- thread->funcname = funcname;
- thread->schedfrom = schedfrom;
- thread->schedfrom_line = fromln;
+ thread->xref = xref;
return thread;
}
@@ -832,21 +827,23 @@ done:
}
/* Add new read thread. */
-struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, int fd,
- struct thread **t_ptr,
- debugargdef)
+struct thread *_thread_add_read_write(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, int fd, struct thread **t_ptr)
{
+ int dir = xref->thread_type;
struct thread *thread = NULL;
struct thread **thread_array;
if (dir == THREAD_READ)
- frrtrace(9, frr_libfrr, schedule_read, m, funcname, schedfrom,
- fromln, t_ptr, fd, 0, arg, 0);
+ frrtrace(9, frr_libfrr, schedule_read, m,
+ xref->funcname, xref->xref.file, xref->xref.line,
+ t_ptr, fd, 0, arg, 0);
else
- frrtrace(9, frr_libfrr, schedule_write, m, funcname, schedfrom,
- fromln, t_ptr, fd, 0, arg, 0);
+ frrtrace(9, frr_libfrr, schedule_write, m,
+ xref->funcname, xref->xref.file, xref->xref.line,
+ t_ptr, fd, 0, arg, 0);
assert(fd >= 0 && fd < m->fd_limit);
frr_with_mutex(&m->mtx) {
@@ -882,7 +879,7 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
/* make sure we have room for this fd + pipe poker fd */
assert(queuepos + 1 < m->handler.pfdsize);
- thread = thread_get(m, dir, func, arg, debugargpass);
+ thread = thread_get(m, dir, func, arg, xref);
m->handler.pfds[queuepos].fd = fd;
m->handler.pfds[queuepos].events |=
@@ -910,32 +907,35 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
}
static struct thread *
-funcname_thread_add_timer_timeval(struct thread_master *m,
- int (*func)(struct thread *), int type,
- void *arg, struct timeval *time_relative,
- struct thread **t_ptr, debugargdef)
+_thread_add_timer_timeval(const struct xref_threadsched *xref,
+ struct thread_master *m, int (*func)(struct thread *),
+ void *arg, struct timeval *time_relative,
+ struct thread **t_ptr)
{
struct thread *thread;
+ struct timeval t;
assert(m != NULL);
- assert(type == THREAD_TIMER);
assert(time_relative);
- frrtrace(9, frr_libfrr, schedule_timer, m, funcname, schedfrom, fromln,
+ frrtrace(9, frr_libfrr, schedule_timer, m,
+ xref->funcname, xref->xref.file, xref->xref.line,
t_ptr, 0, 0, arg, (long)time_relative->tv_sec);
+ /* Compute expiration/deadline time. */
+ monotime(&t);
+ timeradd(&t, time_relative, &t);
+
frr_with_mutex(&m->mtx) {
if (t_ptr && *t_ptr)
/* thread is already scheduled; don't reschedule */
return NULL;
- thread = thread_get(m, type, func, arg, debugargpass);
+ thread = thread_get(m, THREAD_TIMER, func, arg, xref);
frr_with_mutex(&thread->mtx) {
- monotime(&thread->u.sands);
- timeradd(&thread->u.sands, time_relative,
- &thread->u.sands);
+ thread->u.sands = t;
thread_timer_list_add(&m->timer, thread);
if (t_ptr) {
*t_ptr = thread;
@@ -943,7 +943,12 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
}
}
- AWAKEN(m);
+ /* The timer list is sorted - if this new timer
+ * might change the time we'll wait for, give the pthread
+ * a chance to re-compute.
+ */
+ if (thread_timer_list_first(&m->timer) == thread)
+ AWAKEN(m);
}
return thread;
@@ -951,10 +956,10 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
/* Add timer event thread. */
-struct thread *funcname_thread_add_timer(struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, long timer,
- struct thread **t_ptr, debugargdef)
+struct thread *_thread_add_timer(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, long timer, struct thread **t_ptr)
{
struct timeval trel;
@@ -963,16 +968,15 @@ struct thread *funcname_thread_add_timer(struct thread_master *m,
trel.tv_sec = timer;
trel.tv_usec = 0;
- return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
- &trel, t_ptr, debugargpass);
+ return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
}
/* Add timer event thread with "millisecond" resolution */
-struct thread *funcname_thread_add_timer_msec(struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, long timer,
- struct thread **t_ptr,
- debugargdef)
+struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, long timer,
+ struct thread **t_ptr)
{
struct timeval trel;
@@ -981,29 +985,29 @@ struct thread *funcname_thread_add_timer_msec(struct thread_master *m,
trel.tv_sec = timer / 1000;
trel.tv_usec = 1000 * (timer % 1000);
- return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
- &trel, t_ptr, debugargpass);
+ return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
}
-/* Add timer event thread with "millisecond" resolution */
-struct thread *funcname_thread_add_timer_tv(struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, struct timeval *tv,
- struct thread **t_ptr, debugargdef)
+/* Add timer event thread with "timeval" resolution */
+struct thread *_thread_add_timer_tv(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, struct timeval *tv,
+ struct thread **t_ptr)
{
- return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg, tv,
- t_ptr, debugargpass);
+ return _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
}
/* Add simple event thread. */
-struct thread *funcname_thread_add_event(struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, int val,
- struct thread **t_ptr, debugargdef)
+struct thread *_thread_add_event(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, int val, struct thread **t_ptr)
{
struct thread *thread = NULL;
- frrtrace(9, frr_libfrr, schedule_event, m, funcname, schedfrom, fromln,
+ frrtrace(9, frr_libfrr, schedule_event, m,
+ xref->funcname, xref->xref.file, xref->xref.line,
t_ptr, 0, val, arg, 0);
assert(m != NULL);
@@ -1013,7 +1017,7 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
/* thread is already scheduled; don't reschedule */
break;
- thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
+ thread = thread_get(m, THREAD_EVENT, func, arg, xref);
frr_with_mutex(&thread->mtx) {
thread->u.val = val;
thread_list_add_tail(&m->event, thread);
@@ -1239,8 +1243,9 @@ void thread_cancel(struct thread **thread)
master = (*thread)->master;
- frrtrace(9, frr_libfrr, thread_cancel, master, (*thread)->funcname,
- (*thread)->schedfrom, (*thread)->schedfrom_line, NULL, (*thread)->u.fd,
+ frrtrace(9, frr_libfrr, thread_cancel, master,
+ (*thread)->xref->funcname, (*thread)->xref->xref.file,
+ (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
(*thread)->u.val, (*thread)->arg, (*thread)->u.sands.tv_sec);
assert(master->owner == pthread_self());
@@ -1287,8 +1292,8 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread,
if (thread && *thread)
frrtrace(9, frr_libfrr, thread_cancel_async, master,
- (*thread)->funcname, (*thread)->schedfrom,
- (*thread)->schedfrom_line, NULL, (*thread)->u.fd,
+ (*thread)->xref->funcname, (*thread)->xref->xref.file,
+ (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
(*thread)->u.val, (*thread)->arg,
(*thread)->u.sands.tv_sec);
else
@@ -1363,7 +1368,7 @@ static int thread_process_io_helper(struct thread_master *m,
if (!thread) {
if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
flog_err(EC_LIB_NO_THREAD,
- "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n",
+ "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!",
m->handler.pfds[pos].fd, actual_state);
return 0;
}
@@ -1447,20 +1452,21 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
}
/* Add all timers that have popped to the ready list. */
-static unsigned int thread_process_timers(struct thread_timer_list_head *timers,
+static unsigned int thread_process_timers(struct thread_master *m,
struct timeval *timenow)
{
struct thread *thread;
unsigned int ready = 0;
- while ((thread = thread_timer_list_first(timers))) {
+ while ((thread = thread_timer_list_first(&m->timer))) {
if (timercmp(timenow, &thread->u.sands, <))
- return ready;
- thread_timer_list_pop(timers);
+ break;
+ thread_timer_list_pop(&m->timer);
thread->type = THREAD_READY;
- thread_list_add_tail(&thread->master->ready, thread);
+ thread_list_add_tail(&m->ready, thread);
ready++;
}
+
return ready;
}
@@ -1509,9 +1515,13 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
if (fetch->ref)
*fetch->ref = NULL;
pthread_mutex_unlock(&m->mtx);
+ if (!m->ready_run_loop)
+ GETRUSAGE(&m->last_getrusage);
+ m->ready_run_loop = true;
break;
}
+ m->ready_run_loop = false;
/* otherwise, tick through scheduling sequence */
/*
@@ -1582,7 +1592,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
/* Post timers to ready queue. */
monotime(&now);
- thread_process_timers(&m->timer, &now);
+ thread_process_timers(m, &now);
/* Post I/O to ready queue. */
if (num > 0)
@@ -1670,11 +1680,16 @@ void thread_call(struct thread *thread)
#endif
RUSAGE_T before, after;
- GETRUSAGE(&before);
+ if (thread->master->ready_run_loop)
+ before = thread->master->last_getrusage;
+ else
+ GETRUSAGE(&before);
+
thread->real = before.real;
- frrtrace(9, frr_libfrr, thread_call, thread->master, thread->funcname,
- thread->schedfrom, thread->schedfrom_line, NULL, thread->u.fd,
+ frrtrace(9, frr_libfrr, thread_call, thread->master,
+ thread->xref->funcname, thread->xref->xref.file,
+ thread->xref->xref.line, NULL, thread->u.fd,
thread->u.val, thread->arg, thread->u.sands.tv_sec);
pthread_setspecific(thread_current, thread);
@@ -1682,6 +1697,7 @@ void thread_call(struct thread *thread)
pthread_setspecific(thread_current, NULL);
GETRUSAGE(&after);
+ thread->master->last_getrusage = after;
#ifndef EXCLUDE_CPU_TIME
realtime = thread_consumed_time(&after, &before, &helper);
@@ -1724,7 +1740,7 @@ void thread_call(struct thread *thread)
flog_warn(
EC_LIB_SLOW_THREAD,
"SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
- thread->funcname, (unsigned long)thread->func,
+ thread->xref->funcname, (unsigned long)thread->func,
realtime / 1000, cputime / 1000);
}
#endif /* CONSUMED_TIME_CHECK */
@@ -1732,15 +1748,15 @@ void thread_call(struct thread *thread)
}
/* Execute thread */
-void funcname_thread_execute(struct thread_master *m,
- int (*func)(struct thread *), void *arg, int val,
- debugargdef)
+void _thread_execute(const struct xref_threadsched *xref,
+ struct thread_master *m, int (*func)(struct thread *),
+ void *arg, int val)
{
struct thread *thread;
/* Get or allocate new thread to execute. */
frr_with_mutex(&m->mtx) {
- thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
+ thread = thread_get(m, THREAD_EVENT, func, arg, xref);
/* Set its event value. */
frr_with_mutex(&thread->mtx) {