diff options
Diffstat (limited to 'lib/thread.c')
| -rw-r--r-- | lib/thread.c | 180 |
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) { |
