diff --git a/lib/thread.c b/lib/thread.c index 8b6a7e2..095dff4 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -30,7 +30,15 @@ #include "hash.h" #include "command.h" #include "sigevent.h" +/* Recent absolute time of day */ struct timeval recent_time; +static struct timeval last_recent_time; +/* Relative time, since startup */ +static struct timeval relative_time; +static struct timeval relative_time_base; +/* init flag */ +static unsigned short timers_inited; + static struct hash *cpu_record = NULL; /* Struct timeval's tv_usec one second value. */ @@ -85,6 +93,129 @@ timeval_elapsed (struct timeval a, struc + (a.tv_usec - b.tv_usec)); } +#ifndef HAVE_CLOCK_MONOTONIC +static void +quagga_gettimeofday_relative_adjust (void) +{ + struct timeval diff; + if (timeval_cmp (recent_time, last_recent_time) < 0) + { + relative_time.tv_sec++; + relative_time.tv_usec = 0; + } + else + { + diff = timeval_subtract (recent_time, last_recent_time); + relative_time.tv_sec += diff.tv_sec; + relative_time.tv_usec += diff.tv_usec; + relative_time = timeval_adjust (relative_time); + } + last_recent_time = recent_time; +} +#endif /* !HAVE_CLOCK_MONOTONIC */ + +/* gettimeofday wrapper, to keep recent_time updated */ +static int +quagga_gettimeofday (struct timeval *tv) +{ + int ret; + + assert (tv); + + if (!(ret = gettimeofday (&recent_time, NULL))) + { + /* init... */ + if (!timers_inited) + { + relative_time_base = last_recent_time = recent_time; + timers_inited = 1; + } + /* avoid copy if user passed recent_time pointer.. */ + if (tv != &recent_time) + *tv = recent_time; + return 0; + } + return ret; +} + +static int +quagga_get_relative (struct timeval *tv) +{ + int ret; + +#ifdef HAVE_CLOCK_MONOTONIC + { + struct timespec tp; + if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp))) + { + relative_time.tv_sec = tp.tv_sec; + relative_time.tv_usec = tp.tv_nsec / 1000; + } + } +#else /* !HAVE_CLOCK_MONOTONIC */ + if (!(ret = quagga_gettimeofday (&recent_time))) + quagga_gettimeofday_relative_adjust(); +#endif /* HAVE_CLOCK_MONOTONIC */ + + if (tv) + *tv = relative_time; + + return ret; +} + +/* Get absolute time stamp, but in terms of the internal timer + * Could be wrong, but at least won't go back. + */ +static void +quagga_real_stabilised (struct timeval *tv) +{ + *tv = relative_time_base; + tv->tv_sec += relative_time.tv_sec; + tv->tv_usec += relative_time.tv_usec; + *tv = timeval_adjust (*tv); +} + +/* Exported Quagga timestamp function. + * Modelled on POSIX clock_gettime. + */ +int +quagga_gettime (enum quagga_clkid clkid, struct timeval *tv) +{ + switch (clkid) + { + case QUAGGA_CLK_REALTIME: + return quagga_gettimeofday (tv); + case QUAGGA_CLK_MONOTONIC: + return quagga_get_relative (tv); + case QUAGGA_CLK_REALTIME_STABILISED: + quagga_real_stabilised (tv); + return 0; + default: + errno = EINVAL; + return -1; + } +} + +/* time_t value in terms of stabilised absolute time. + * replacement for POSIX time() + */ +time_t +quagga_time (time_t *t) +{ + struct timeval tv; + quagga_real_stabilised (&tv); + if (t) + *t = tv.tv_sec; + return tv.tv_sec; +} + +/* Public export of recent_relative_time by value */ +struct timeval +recent_relative_time (void) +{ + return relative_time; +} + static unsigned int cpu_record_hash_key (struct cpu_thread_history *a) { @@ -396,10 +527,10 @@ thread_trim_head (struct thread_list *li unsigned long thread_timer_remain_second (struct thread *thread) { - gettimeofday (&recent_time, NULL); - - if (thread->u.sands.tv_sec - recent_time.tv_sec > 0) - return thread->u.sands.tv_sec - recent_time.tv_sec; + quagga_get_relative (NULL); + + if (thread->u.sands.tv_sec - relative_time.tv_sec > 0) + return thread->u.sands.tv_sec - relative_time.tv_sec; else return 0; } @@ -515,8 +646,8 @@ funcname_thread_add_timer_timeval (struc const char* funcname) { struct thread *thread; - struct timeval alarm_time; struct thread_list *list; + struct timeval alarm_time; struct thread *tt; assert (m != NULL); @@ -528,9 +659,9 @@ funcname_thread_add_timer_timeval (struc thread = thread_get (m, type, func, arg, funcname); /* Do we need jitter here? */ - gettimeofday (&recent_time, NULL); - alarm_time.tv_sec = recent_time.tv_sec + time_relative->tv_sec; - alarm_time.tv_usec = recent_time.tv_usec + time_relative->tv_usec; + quagga_gettimeofday (&recent_time); + 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. */ @@ -693,7 +824,7 @@ thread_timer_wait (struct thread_list *t { if (!thread_empty (tlist)) { - *timer_val = timeval_subtract (tlist->head->u.sands, recent_time); + *timer_val = timeval_subtract (tlist->head->u.sands, relative_time); return timer_val; } return NULL; @@ -790,7 +921,7 @@ thread_fetch (struct thread_master *m, s exceptfd = m->exceptfd; /* Calculate select wait timer if nothing else to do */ - gettimeofday (&recent_time, NULL); + quagga_get_relative (NULL); timer_wait = thread_timer_wait (&m->timer, &timer_val); timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg); @@ -812,8 +943,8 @@ thread_fetch (struct thread_master *m, s /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ - gettimeofday (&recent_time, NULL); - thread_timer_process (&m->timer, &recent_time); + quagga_get_relative (NULL); + thread_timer_process (&m->timer, &relative_time); /* Got IO, process it */ if (num > 0) @@ -834,7 +965,7 @@ #if 0 #endif /* Background timer/events, lowest priority */ - thread_timer_process (&m->background, &recent_time); + thread_timer_process (&m->background, &relative_time); if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); @@ -866,11 +997,29 @@ #endif /* HAVE_RUSAGE */ int thread_should_yield (struct thread *thread) { - gettimeofday(&recent_time, NULL); - return (timeval_elapsed(recent_time, thread->ru.real) > + quagga_get_relative (NULL); + return (timeval_elapsed(relative_time, thread->ru.real) > THREAD_YIELD_TIME_SLOT); } +void +thread_getrusage (RUSAGE_T *r) +{ + quagga_get_relative (NULL); +#ifdef HAVE_RUSAGE + getrusage(RUSAGE_SELF, &(r->cpu)); +#endif + r->real = relative_time; + +#ifdef HAVE_CLOCK_MONOTONIC + /* quagga_get_relative() only updates recent_time if gettimeofday + * based, not when using CLOCK_MONOTONIC. As we export recent_time + * and guarantee to update it before threads are run... + */ + quagga_gettimeofday(&recent_time); +#endif /* HAVE_CLOCK_MONOTONIC */ +} + /* 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 to wall clock time stats from gettimeofday. */ diff --git a/lib/thread.h b/lib/thread.h index 0670a89..1c324d8 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -31,14 +31,7 @@ #endif }; #define RUSAGE_T struct rusage_t -#ifdef HAVE_RUSAGE -#define GETRUSAGE(X) \ - getrusage(RUSAGE_SELF, &((X)->cpu)); \ - gettimeofday(&recent_time, NULL); (X)->real = recent_time -#else -#define GETRUSAGE(X) \ - gettimeofday(&recent_time, NULL); (X)->real = recent_time -#endif /* HAVE_RUSAGE */ +#define GETRUSAGE(X) thread_getrusage(X) /* Linked list of thread. */ struct thread_list @@ -99,6 +92,13 @@ #endif unsigned char types; }; +/* Clocks supported by Quagga */ +enum quagga_clkid { + QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */ + QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */ + QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */ +}; + /* Thread types. */ #define THREAD_READ 0 #define THREAD_WRITE 1 @@ -192,8 +192,17 @@ extern void thread_call (struct thread * extern unsigned long thread_timer_remain_second (struct thread *); extern int thread_should_yield (struct thread *); +/* Internal libzebra exports */ +extern void thread_getrusage (RUSAGE_T *); extern struct cmd_element show_thread_cpu_cmd; +/* replacements for the system gettimeofday(), clock_gettime() and + * time() functions, providing support for non-decrementing clock on + * all systems, and fully monotonic on /some/ systems. + */ +extern int quagga_gettime (enum quagga_clkid, struct timeval *); +extern time_t quagga_time (time_t *); + /* Returns elapsed real (wall clock) time. */ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, unsigned long *cpu_time_elapsed); @@ -202,5 +211,6 @@ extern unsigned long thread_consumed_tim be used instead of calling gettimeofday if a recent value is sufficient. This is guaranteed to be refreshed before a thread is called. */ extern struct timeval recent_time; - +/* Similar to recent_time, but a monotonically increasing time value */ +extern struct timeval recent_relative_time (void); #endif /* _ZEBRA_THREAD_H */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index b8dc795..2fcbfe6 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -300,7 +300,7 @@ ospf_timer_dump (struct thread *t, char if (!t) return "inactive"; - result = tv_sub (t->u.sands, recent_time); + result = tv_sub (t->u.sands, recent_relative_time()); return ospf_timeval_dump (&result, buf, size); } diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 91cbbf3..0f485fe 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -268,7 +268,7 @@ ospf_flood (struct ospf *ospf, struct os "while local one is initial instance."); ; /* Accept this LSA for quick LSDB resynchronization. */ } - else if (tv_cmp (tv_sub (recent_time, current->tv_recv), + else if (tv_cmp (tv_sub (recent_relative_time (), current->tv_recv), int2tv (OSPF_MIN_LS_ARRIVAL)) < 0) { if (IS_DEBUG_OSPF_EVENT) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index b99b931..05eed35 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -141,7 +141,7 @@ ospf_lsa_refresh_delay (struct ospf_lsa struct timeval delta, now; int delay = 0; - gettimeofday (&now, NULL); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); delta = tv_sub (now, lsa->tv_orig); if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) @@ -163,10 +163,9 @@ int get_age (struct ospf_lsa *lsa) { int age; - struct timeval now; - gettimeofday (&now, NULL); - age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv)); + age = ntohs (lsa->data->ls_age) + + tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv)); return age; } @@ -229,7 +228,7 @@ ospf_lsa_new () new->flags = 0; new->lock = 1; new->retransmit_counter = 0; - gettimeofday (&new->tv_recv, NULL); + new->tv_recv = recent_relative_time (); new->tv_orig = new->tv_recv; new->refresh_list = -1; @@ -2460,9 +2459,6 @@ ospf_external_lsa_refresh (struct ospf * new->data->ls_seqnum = lsa_seqnum_increment (lsa); - /* Record timestamp. */ - gettimeofday (&new->tv_orig, NULL); - /* Re-calculate checksum. */ ospf_lsa_checksum (new->data); @@ -3770,7 +3766,7 @@ ospf_refresher_register_lsa (struct ospf delay = 0; current_index = ospf->lsa_refresh_queue.index + - (time (NULL) - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; + (quagga_time (NULL) - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) % (OSPF_LSA_REFRESHER_SLOTS); @@ -3829,7 +3825,7 @@ ospf_lsa_refresh_walker (struct thread * modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index + - (time (NULL) - ospf->lsa_refresher_started) / + (quagga_time (NULL) - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS; if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) @@ -3867,7 +3863,7 @@ ospf_lsa_refresh_walker (struct thread * ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, ospf->lsa_refresh_interval); - ospf->lsa_refresher_started = time (NULL); + ospf->lsa_refresher_started = quagga_time (NULL); for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) ospf_lsa_refresh (ospf, lsa); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index e3517cd..69bd48c 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -617,10 +617,10 @@ nsm_notice_state_change (struct ospf_nei /* Advance in NSM */ if (next_state > nbr->state) - nbr->ts_last_progress = recent_time; + nbr->ts_last_progress = recent_relative_time (); else /* regression in NSM */ { - nbr->ts_last_regress = recent_time; + nbr->ts_last_regress = recent_relative_time (); nbr->last_regress_str = ospf_nsm_event_str [event]; } @@ -747,7 +747,7 @@ #endif /* HAVE_OPAQUE_LSA */ if (state == NSM_ExStart) { if (nbr->dd_seqnum == 0) - nbr->dd_seqnum = time (NULL); + nbr->dd_seqnum = quagga_time (NULL); else nbr->dd_seqnum++; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 6449e63..3fdf150 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -444,7 +444,7 @@ ospf_ls_upd_timer (struct thread *thread fired. This is a small tweak to what is in the RFC, but it will cut out out a lot of retransmit traffic - MAG */ - if (tv_cmp (tv_sub (recent_time, lsa->tv_recv), + if (tv_cmp (tv_sub (recent_relative_time (), lsa->tv_recv), int2tv (retransmit_interval)) >= 0) listnode_add (update, rn->info); } @@ -1363,7 +1363,7 @@ #endif /* ORIGINAL_CODING */ else { struct timeval t, now; - gettimeofday (&now, NULL); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); t = tv_sub (now, nbr->last_send_ts); if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0) { @@ -1948,7 +1948,7 @@ #endif /* HAVE_OPAQUE_LSA */ { struct timeval now; - gettimeofday (&now, NULL); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (tv_cmp (tv_sub (now, current->tv_orig), int2tv (OSPF_MIN_LS_ARRIVAL)) > 0) @@ -3158,7 +3158,7 @@ ospf_db_desc_send (struct ospf_neighbor if (nbr->last_send) ospf_packet_free (nbr->last_send); nbr->last_send = ospf_packet_dup (op); - gettimeofday (&nbr->last_send_ts, NULL); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts); } /* Re-send Database Description. */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index e0f2565..3a1fa99 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -47,7 +47,7 @@ ospf_route_new () new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); - new->ctime = time (NULL); + new->ctime = quagga_time (NULL); new->mtime = new->ctime; new->paths = list_new (); new->paths->del = (void (*) (void *))ospf_path_free; diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 7228d2d..a133d5f 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1136,7 +1136,7 @@ ospf_spf_calculate (struct ospf_area *ar /* Increment SPF Calculation Counter. */ area->spf_calculation++; - gettimeofday (&area->ospf->ts_spf, NULL); + quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", @@ -1243,7 +1243,7 @@ ospf_spf_calculate_schedule (struct ospf } /* XXX Monotic timers: we only care about relative time here. */ - result = tv_sub (recent_time, ospf->ts_spf); + result = tv_sub (recent_relative_time (), ospf->ts_spf); elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); ht = ospf->spf_holdtime * ospf->spf_hold_multiplier; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 912f1d0..04e1df4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2691,7 +2691,7 @@ #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " SPF algorithm "); if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec) { - result = tv_sub (recent_time, ospf->ts_spf); + result = tv_sub (recent_relative_time (), ospf->ts_spf); vty_out (vty, "last executed %s ago%s", ospf_timeval_dump (&result, timebuf, sizeof (timebuf)), VTY_NEWLINE); @@ -3157,7 +3157,8 @@ show_ip_ospf_neighbor_detail_sub (struct vty_out (vty, " %d state changes%s", nbr->state_change, VTY_NEWLINE); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { - struct timeval res = tv_sub (recent_time, nbr->ts_last_progress); + struct timeval res + = tv_sub (recent_relative_time (), nbr->ts_last_progress); vty_out (vty, " Most recent state change statistics:%s", VTY_NEWLINE); vty_out (vty, " Progressive change %s ago%s", @@ -3166,7 +3167,8 @@ show_ip_ospf_neighbor_detail_sub (struct } if (nbr->ts_last_regress.tv_sec || nbr->ts_last_regress.tv_usec) { - struct timeval res = tv_sub (recent_time, nbr->ts_last_regress); + struct timeval res + = tv_sub (recent_relative_time (), nbr->ts_last_regress); vty_out (vty, " Regressive change %s ago, due to %s%s", ospf_timeval_dump (&res, timebuf, sizeof(timebuf)), (nbr->last_regress_str ? nbr->last_regress_str : "??"), diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 95615e4..a1f0f01 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -202,7 +202,7 @@ ospf_new (void) new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, new, new->lsa_refresh_interval); - new->lsa_refresher_started = time (NULL); + new->lsa_refresher_started = quagga_time (NULL); if ((new->fd = ospf_sock_init()) < 0) { @@ -1317,7 +1317,7 @@ ospf_timers_refresh_set (struct ospf *os return 1; time_left = ospf->lsa_refresh_interval - - (time (NULL) - ospf->lsa_refresher_started); + (quagga_time (NULL) - ospf->lsa_refresher_started); if (time_left > interval) { @@ -1336,7 +1336,7 @@ ospf_timers_refresh_unset (struct ospf * int time_left; time_left = ospf->lsa_refresh_interval - - (time (NULL) - ospf->lsa_refresher_started); + (quagga_time (NULL) - ospf->lsa_refresher_started); if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) { @@ -1657,5 +1657,5 @@ ospf_master_init () om = &ospf_master; om->ospf = list_new (); om->master = thread_master_create (); - om->start_time = time (NULL); + om->start_time = quagga_time (NULL); }