Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_tc.c
Show All 22 Lines | |||||
#include "opt_ntp.h" | #include "opt_ntp.h" | ||||
#include "opt_ffclock.h" | #include "opt_ffclock.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/proc.h> | |||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/sleepqueue.h> | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/timeffc.h> | #include <sys/timeffc.h> | ||||
#include <sys/timepps.h> | #include <sys/timepps.h> | ||||
#include <sys/timetc.h> | #include <sys/timetc.h> | ||||
#include <sys/timex.h> | #include <sys/timex.h> | ||||
#include <sys/vdso.h> | #include <sys/vdso.h> | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
int tc_precexp; | int tc_precexp; | ||||
int tc_timepercentage = TC_DEFAULTPERC; | int tc_timepercentage = TC_DEFAULTPERC; | ||||
static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS); | static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS); | ||||
SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, | SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, | ||||
CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, | CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, | ||||
sysctl_kern_timecounter_adjprecision, "I", | sysctl_kern_timecounter_adjprecision, "I", | ||||
"Allowed time interval deviation in percents"); | "Allowed time interval deviation in percents"); | ||||
volatile int rtc_generation = 1; | |||||
static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */ | static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */ | ||||
static void tc_windup(struct bintime *new_boottimebin); | static void tc_windup(struct bintime *new_boottimebin); | ||||
static void cpu_tick_calibrate(int); | static void cpu_tick_calibrate(int); | ||||
void dtrace_getnanotime(struct timespec *tsp); | void dtrace_getnanotime(struct timespec *tsp); | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 1,119 Lines • ▼ Show 20 Lines | |||||
/* Report the frequency of the current timecounter. */ | /* Report the frequency of the current timecounter. */ | ||||
uint64_t | uint64_t | ||||
tc_getfrequency(void) | tc_getfrequency(void) | ||||
{ | { | ||||
return (timehands->th_counter->tc_frequency); | return (timehands->th_counter->tc_frequency); | ||||
} | } | ||||
static bool | |||||
sleeping_on_old_rtc(struct thread *td) | |||||
{ | |||||
if (td->td_rtcgen != 0 && | |||||
td->td_rtcgen != atomic_load_acq_int(&rtc_generation)) { | |||||
td->td_rtcgen = 0; | |||||
kib: By finding the thread on a sleepqueue and holding the lock ... | |||||
Not Done Inline ActionsThat sounds better. vangyzen: That sounds better. | |||||
return (true); | |||||
} | |||||
kibUnsubmitted Done Inline ActionsBlank line is not needed. kib: Blank line is not needed. | |||||
return (false); | |||||
} | |||||
static struct mtx tc_setclock_mtx; | static struct mtx tc_setclock_mtx; | ||||
MTX_SYSINIT(tc_setclock_init, &tc_setclock_mtx, "tcsetc", MTX_SPIN); | MTX_SYSINIT(tc_setclock_init, &tc_setclock_mtx, "tcsetc", MTX_SPIN); | ||||
/* | /* | ||||
* Step our concept of UTC. This is done by modifying our estimate of | * Step our concept of UTC. This is done by modifying our estimate of | ||||
* when we booted. | * when we booted. | ||||
*/ | */ | ||||
void | void | ||||
tc_setclock(struct timespec *ts) | tc_setclock(struct timespec *ts) | ||||
{ | { | ||||
struct timespec tbef, taft; | struct timespec tbef, taft; | ||||
struct bintime bt, bt2; | struct bintime bt, bt2; | ||||
timespec2bintime(ts, &bt); | timespec2bintime(ts, &bt); | ||||
nanotime(&tbef); | nanotime(&tbef); | ||||
mtx_lock_spin(&tc_setclock_mtx); | mtx_lock_spin(&tc_setclock_mtx); | ||||
cpu_tick_calibrate(1); | cpu_tick_calibrate(1); | ||||
binuptime(&bt2); | binuptime(&bt2); | ||||
bintime_sub(&bt, &bt2); | bintime_sub(&bt, &bt2); | ||||
/* XXX fiddle all the little crinkly bits around the fiords... */ | /* XXX fiddle all the little crinkly bits around the fiords... */ | ||||
tc_windup(&bt); | tc_windup(&bt); | ||||
mtx_unlock_spin(&tc_setclock_mtx); | mtx_unlock_spin(&tc_setclock_mtx); | ||||
/* Avoid rtc_generation == 0, since td_rtcgen == 0 is special. */ | |||||
Done Inline ActionsWhy do you need enqueue_timeout() ? I do not quite understand why cannot you directly call sleepq_remove_matching() in the current context. kib: Why do you need enqueue_timeout() ? I do not quite understand why cannot you directly call… | |||||
Done Inline ActionsMy understanding of style(9) would require a blank line before the comment. jhb: My understanding of style(9) would require a blank line before the comment. | |||||
Not Done Inline ActionsI couldn't find the reference, but I like an extra line here anyway. vangyzen: I couldn't find the reference, but I like an extra line here anyway. | |||||
atomic_add_rel_int(&rtc_generation, 2); | |||||
sleepq_chains_remove_matching(sleeping_on_old_rtc); | |||||
if (timestepwarnings) { | if (timestepwarnings) { | ||||
nanotime(&taft); | nanotime(&taft); | ||||
log(LOG_INFO, | log(LOG_INFO, | ||||
"Time stepped from %jd.%09ld to %jd.%09ld (%jd.%09ld)\n", | "Time stepped from %jd.%09ld to %jd.%09ld (%jd.%09ld)\n", | ||||
(intmax_t)tbef.tv_sec, tbef.tv_nsec, | (intmax_t)tbef.tv_sec, tbef.tv_nsec, | ||||
(intmax_t)taft.tv_sec, taft.tv_nsec, | (intmax_t)taft.tv_sec, taft.tv_nsec, | ||||
(intmax_t)ts->tv_sec, ts->tv_nsec); | (intmax_t)ts->tv_sec, ts->tv_nsec); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | case SYSCLOCK_FFWD: | ||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
timehands = th; | timehands = th; | ||||
timekeep_push_vdso(); | timekeep_push_vdso(); | ||||
} | } | ||||
/* Report or change the active timecounter hardware. */ | /* Report or change the active timecounter hardware. */ | ||||
Done Inline ActionsI think it is fine to increment generation in tc_setclock, after the tc_setclock_mtx spinlock is unlocked, right before remove_matching(). Also, the increment must be slightly more advanced, to avoid overflowing the value into zero. kib: I think it is fine to increment generation in tc_setclock, after the tc_setclock_mtx spinlock… | |||||
Done Inline ActionsI agree about the location. I figured overflow wouldn't happen in practice, but guaranteeing it is easy enough, so I will. vangyzen: I agree about the location.
I figured overflow wouldn't happen in practice, but guaranteeing… | |||||
static int | static int | ||||
sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) | sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
char newname[32]; | char newname[32]; | ||||
struct timecounter *newtc, *tc; | struct timecounter *newtc, *tc; | ||||
int error; | int error; | ||||
tc = timecounter; | tc = timecounter; | ||||
▲ Show 20 Lines • Show All 699 Lines • Show Last 20 Lines |
By finding the thread on a sleepqueue and holding the lock ...