📄 kern_clock.c
字号:
*/ clkinfo.hz = hz; clkinfo.tick = tick; clkinfo.tickadj = tickadj; clkinfo.profhz = profhz; clkinfo.stathz = stathz ? stathz : hz; return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req));}SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 0, 0, sysctl_kern_clockrate, "S,clockinfo","");#endif /* !OSKIT */static __inline unsignedtco_delta(struct timecounter *tc){ return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) & tc->tc_counter_mask);}/* * We have four functions for looking at the clock, two for microseconds * and two for nanoseconds. For each there is fast but less precise * version "get{nano|micro}time" which will return a time which is up * to 1/HZ previous to the call, whereas the raw version "{nano|micro}time" * will return a timestamp which is as precise as possible. */voidgetmicrotime(struct timeval *tvp){ struct timecounter *tc; if (!tco_method) { tc = timecounter; *tvp = tc->tc_microtime; } else { microtime(tvp); }}voidgetnanotime(struct timespec *tsp){ struct timecounter *tc; if (!tco_method) { tc = timecounter; *tsp = tc->tc_nanotime; } else { nanotime(tsp); }}voidmicrotime(struct timeval *tv){ struct timecounter *tc; tc = (struct timecounter *)timecounter; tv->tv_sec = tc->tc_offset_sec; tv->tv_usec = tc->tc_offset_micro; tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; tv->tv_usec += boottime.tv_usec; tv->tv_sec += boottime.tv_sec; while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; }}voidnanotime(struct timespec *ts){ unsigned count; u_int64_t delta; struct timecounter *tc; tc = (struct timecounter *)timecounter; ts->tv_sec = tc->tc_offset_sec; count = tco_delta(tc); delta = tc->tc_offset_nano; delta += ((u_int64_t)count * tc->tc_scale_nano_f); delta >>= 32; delta += ((u_int64_t)count * tc->tc_scale_nano_i); delta += boottime.tv_usec * 1000; ts->tv_sec += boottime.tv_sec; while (delta >= 1000000000) { delta -= 1000000000; ts->tv_sec++; } ts->tv_nsec = delta;}voidtimecounter_timespec(unsigned count, struct timespec *ts){ u_int64_t delta; struct timecounter *tc; tc = (struct timecounter *)timecounter; ts->tv_sec = tc->tc_offset_sec; count -= tc->tc_offset_count; count &= tc->tc_counter_mask; delta = tc->tc_offset_nano; delta += ((u_int64_t)count * tc->tc_scale_nano_f); delta >>= 32; delta += ((u_int64_t)count * tc->tc_scale_nano_i); delta += boottime.tv_usec * 1000; ts->tv_sec += boottime.tv_sec; while (delta >= 1000000000) { delta -= 1000000000; ts->tv_sec++; } ts->tv_nsec = delta;}voidgetmicrouptime(struct timeval *tvp){ struct timecounter *tc; if (!tco_method) { tc = timecounter; tvp->tv_sec = tc->tc_offset_sec; tvp->tv_usec = tc->tc_offset_micro; } else { microuptime(tvp); }}voidgetnanouptime(struct timespec *tsp){ struct timecounter *tc; if (!tco_method) { tc = timecounter; tsp->tv_sec = tc->tc_offset_sec; tsp->tv_nsec = tc->tc_offset_nano >> 32; } else { nanouptime(tsp); }}voidmicrouptime(struct timeval *tv){ struct timecounter *tc; tc = (struct timecounter *)timecounter; tv->tv_sec = tc->tc_offset_sec; tv->tv_usec = tc->tc_offset_micro; tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; }}voidnanouptime(struct timespec *ts){ unsigned count; u_int64_t delta; struct timecounter *tc; tc = (struct timecounter *)timecounter; ts->tv_sec = tc->tc_offset_sec; count = tco_delta(tc); delta = tc->tc_offset_nano; delta += ((u_int64_t)count * tc->tc_scale_nano_f); delta >>= 32; delta += ((u_int64_t)count * tc->tc_scale_nano_i); if (delta >= 1000000000) { delta -= 1000000000; ts->tv_sec++; } ts->tv_nsec = delta;}static voidtco_setscales(struct timecounter *tc){ u_int64_t scale; scale = 1000000000LL << 32; if (tc->tc_adjustment > 0) scale += (tc->tc_adjustment * 1000LL) << 10; else scale -= (-tc->tc_adjustment * 1000LL) << 10; scale /= tc->tc_frequency; tc->tc_scale_micro = scale / 1000; tc->tc_scale_nano_f = scale & 0xffffffff; tc->tc_scale_nano_i = scale >> 32;}voidinit_timecounter(struct timecounter *tc){ struct timespec ts1; struct timecounter *t1, *t2, *t3; int i; tc->tc_adjustment = 0; tco_setscales(tc); tc->tc_offset_count = tc->tc_get_timecount(tc); tc->tc_tweak = tc; MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK); *t1 = *tc; t2 = t1; for (i = 1; i < NTIMECOUNTER; i++) { MALLOC(t3, struct timecounter *, sizeof *t3, M_TIMECOUNTER, M_WAITOK); *t3 = *tc; t3->tc_other = t2; t2 = t3; } t1->tc_other = t3; tc = t1;#ifndef OSKIT printf("Timecounter \"%s\" frequency %lu Hz\n", tc->tc_name, (u_long)tc->tc_frequency);#endif /* XXX: For now always start using the counter. */ tc->tc_offset_count = tc->tc_get_timecount(tc); nanouptime(&ts1); tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32; tc->tc_offset_micro = ts1.tv_nsec / 1000; tc->tc_offset_sec = ts1.tv_sec; timecounter = tc;}voidset_timecounter(struct timespec *ts){ struct timespec ts2; nanouptime(&ts2); boottime.tv_sec = ts->tv_sec - ts2.tv_sec; boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; if (boottime.tv_usec < 0) { boottime.tv_usec += 1000000; boottime.tv_sec--; } /* fiddle all the little crinkly bits around the fiords... */ tco_forward(1);}#if 0 /* Currently unused */voidswitch_timecounter(struct timecounter *newtc){ int s; struct timecounter *tc; struct timespec ts; s = splclock(); tc = timecounter; if (newtc == tc || newtc == tc->tc_other) { splx(s); return; } nanouptime(&ts); newtc->tc_offset_sec = ts.tv_sec; newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32; newtc->tc_offset_micro = ts.tv_nsec / 1000; newtc->tc_offset_count = newtc->tc_get_timecount(newtc); timecounter = newtc; splx(s);}#endifstatic struct timecounter *sync_other_counter(void){ struct timecounter *tc, *tcn, *tco; unsigned delta; tco = timecounter; tc = tco->tc_other; tcn = tc->tc_other; *tc = *tco; tc->tc_other = tcn; delta = tco_delta(tc); tc->tc_offset_count += delta; tc->tc_offset_count &= tc->tc_counter_mask; tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f; tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32; return (tc);}static voidtco_forward(int force){ struct timecounter *tc, *tco; tco = timecounter; tc = sync_other_counter(); /* * We may be inducing a tiny error here, the tc_poll_pps() may * process a latched count which happens after the tco_delta() * in sync_other_counter(), which would extend the previous * counters parameters into the domain of this new one. * Since the timewindow is very small for this, the error is * going to be only a few weenieseconds (as Dave Mills would * say), so lets just not talk more about it, OK ? */ if (tco->tc_poll_pps) tco->tc_poll_pps(tco);#ifndef OSKIT if (timedelta != 0) { tc->tc_offset_nano += (u_int64_t)(tickdelta * 1000) << 32; timedelta -= tickdelta; force++; }#endif while (tc->tc_offset_nano >= 1000000000ULL << 32) { tc->tc_offset_nano -= 1000000000ULL << 32; tc->tc_offset_sec++; tc->tc_frequency = tc->tc_tweak->tc_frequency; tc->tc_adjustment = tc->tc_tweak->tc_adjustment;#ifndef OSKIT ntp_update_second(tc); /* XXX only needed if xntpd runs */#endif tco_setscales(tc); force++; } if (tco_method && !force) return; tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32; /* Figure out the wall-clock time */ tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec; tc->tc_nanotime.tv_nsec = (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000; tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec; if (tc->tc_nanotime.tv_nsec >= 1000000000) { tc->tc_nanotime.tv_nsec -= 1000000000; tc->tc_microtime.tv_usec -= 1000000; tc->tc_nanotime.tv_sec++; } time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec; timecounter = tc;}static intsysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS{ return (sysctl_handle_opaque(oidp, &timecounter->tc_tweak->tc_frequency, sizeof(timecounter->tc_tweak->tc_frequency), req));}static intsysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS{ return (sysctl_handle_opaque(oidp, &timecounter->tc_tweak->tc_adjustment, sizeof(timecounter->tc_tweak->tc_adjustment), req));}SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0, "This variable determines the method used for updating timecounters. " "If the default algorithm (0) fails with \"calcru negative...\" messages " "try the alternate algorithm (1) which handles bad hardware better.");SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", "");SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", "");intpps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps){ pps_params_t *app; pps_info_t *api; switch (cmd) { case PPS_IOC_CREATE: return (0); case PPS_IOC_DESTROY: return (0); case PPS_IOC_SETPARAMS: app = (pps_params_t *)data; if (app->mode & ~pps->ppscap) return (EINVAL); pps->ppsparam = *app; return (0); case PPS_IOC_GETPARAMS: app = (pps_params_t *)data; *app = pps->ppsparam; return (0); case PPS_IOC_GETCAP: *(int*)data = pps->ppscap; return (0); case PPS_IOC_FETCH: api = (pps_info_t *)data; pps->ppsinfo.current_mode = pps->ppsparam.mode; *api = pps->ppsinfo; return (0); case PPS_IOC_WAIT: return (EOPNOTSUPP); default: return (ENOTTY); }}voidpps_init(struct pps_state *pps){ pps->ppscap |= PPS_TSFMT_TSPEC; if (pps->ppscap & PPS_CAPTUREASSERT) pps->ppscap |= PPS_OFFSETASSERT; if (pps->ppscap & PPS_CAPTURECLEAR) pps->ppscap |= PPS_OFFSETCLEAR;#ifdef PPS_SYNC if (pps->ppscap & PPS_CAPTUREASSERT) pps->ppscap |= PPS_HARDPPSONASSERT; if (pps->ppscap & PPS_CAPTURECLEAR) pps->ppscap |= PPS_HARDPPSONCLEAR;#endif}voidpps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event){ struct timespec ts, *tsp, *osp; u_int64_t delta; unsigned tcount, *pcount; int foff, fhard; pps_seq_t *pseq; /* Things would be easier with arrays... */ if (event == PPS_CAPTUREASSERT) { tsp = &pps->ppsinfo.assert_timestamp; osp = &pps->ppsparam.assert_offset; foff = pps->ppsparam.mode & PPS_OFFSETASSERT; fhard = pps->ppsparam.mode & PPS_HARDPPSONASSERT; pcount = &pps->ppscount[0]; pseq = &pps->ppsinfo.assert_sequence; } else { tsp = &pps->ppsinfo.clear_timestamp; osp = &pps->ppsparam.clear_offset; foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; fhard = pps->ppsparam.mode & PPS_HARDPPSONCLEAR; pcount = &pps->ppscount[1]; pseq = &pps->ppsinfo.clear_sequence; } /* The timecounter changed: bail */ if (!pps->ppstc || pps->ppstc->tc_name != tc->tc_name || tc->tc_name != timecounter->tc_name) { pps->ppstc = tc; *pcount = count; return; } /* Nothing really happened */ if (*pcount == count) return; *pcount = count; /* Convert the count to timespec */ ts.tv_sec = tc->tc_offset_sec; tcount = count - tc->tc_offset_count; tcount &= tc->tc_counter_mask; delta = tc->tc_offset_nano; delta += ((u_int64_t)tcount * tc->tc_scale_nano_f); delta >>= 32; delta += ((u_int64_t)tcount * tc->tc_scale_nano_i); delta += boottime.tv_usec * 1000; ts.tv_sec += boottime.tv_sec; while (delta >= 1000000000) { delta -= 1000000000; ts.tv_sec++; } ts.tv_nsec = delta; (*pseq)++; *tsp = ts; if (foff) { timespecadd(tsp, osp); if (tsp->tv_nsec < 0) { tsp->tv_nsec += 1000000000; tsp->tv_sec -= 1; } }#ifdef PPS_SYNC if (fhard) { /* magic, at its best... */ tcount = count - pps->ppscount[2]; pps->ppscount[2] = count; tcount &= tc->tc_counter_mask; delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f); delta >>= 32; delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i); hardpps(tsp, delta); }#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -