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/taskqueue.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> | ||||
/* | /* | ||||
* A large step happens on boot. This constant detects such steps. | * A large step happens on boot. This constant detects such steps. | ||||
▲ Show 20 Lines • Show All 1,213 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 struct timeout_task rtc_sleepers_awake_task; | |||||
static bool | |||||
sleeping_on_rtc(struct thread *td) | |||||
{ | |||||
THREAD_LOCK_ASSERT(td, MA_OWNED); | |||||
kib: By finding the thread on a sleepqueue and holding the lock ... | |||||
Not Done Inline ActionsThat sounds better. vangyzen: That sounds better. | |||||
if (td->td_flags & TDF_SLEEPRTC) { | |||||
td->td_flags &= ~TDF_SLEEPRTC; | |||||
return (true); | |||||
Done Inline ActionsBlank line is not needed. kib: Blank line is not needed. | |||||
} | |||||
return (false); | |||||
} | |||||
static void | |||||
rtc_sleepers_awake(void *context __unused, int pending __unused) | |||||
{ | |||||
sleepq_remove_matching(sleeping_on_rtc); | |||||
} | |||||
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); | ||||
taskqueue_enqueue_timeout(taskqueue_thread, &rtc_sleepers_awake_task, | |||||
kibUnsubmitted 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. | |||||
hz/100); | |||||
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 483 Lines • ▼ Show 20 Lines | #ifdef FFCLOCK | ||||
ffclock_init(); | ffclock_init(); | ||||
#endif | #endif | ||||
/* warm up new timecounter (again) and get rolling. */ | /* warm up new timecounter (again) and get rolling. */ | ||||
(void)timecounter->tc_get_timecount(timecounter); | (void)timecounter->tc_get_timecount(timecounter); | ||||
(void)timecounter->tc_get_timecount(timecounter); | (void)timecounter->tc_get_timecount(timecounter); | ||||
mtx_lock_spin(&tc_setclock_mtx); | mtx_lock_spin(&tc_setclock_mtx); | ||||
tc_windup(NULL); | tc_windup(NULL); | ||||
mtx_unlock_spin(&tc_setclock_mtx); | mtx_unlock_spin(&tc_setclock_mtx); | ||||
TIMEOUT_TASK_INIT(taskqueue_thread, &rtc_sleepers_awake_task, 0, | |||||
rtc_sleepers_awake, NULL); | |||||
} | } | ||||
SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); | SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); | ||||
/* Cpu tick handling -------------------------------------------------*/ | /* Cpu tick handling -------------------------------------------------*/ | ||||
static int cpu_tick_variable; | static int cpu_tick_variable; | ||||
static uint64_t cpu_tick_frequency; | static uint64_t cpu_tick_frequency; | ||||
▲ Show 20 Lines • Show All 200 Lines • Show Last 20 Lines |
By finding the thread on a sleepqueue and holding the lock ...