⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ktime.c

📁 内核中关于nano计时的功能
💻 C
📖 第 1 页 / 共 2 页
字号:
#endif /* NTP_NANO */		tvp->tv_sec++;		time_maxerror += MAXFREQ / 1000;		/*		 * Leap second processing. If in leap-insert state at		 * the end of the day, the system clock is set back one		 * second; if in leap-delete state, the system clock is		 * set ahead one second. The nano_time() routine or		 * external clock driver will insure that reported time		 * is always monotonic.		 */		switch (time_state) {			/*			 * No warning.			 */			case TIME_OK:			if (time_status & STA_INS)				time_state = TIME_INS;			else if (time_status & STA_DEL)				time_state = TIME_DEL;			break;			/*			 * Insert second 23:59:60 following second			 * 23:59:59.			 */			case TIME_INS:			if (!(time_status & STA_INS))				time_state = TIME_OK;			else if (tvp->tv_sec % 86400 == 0) {				tvp->tv_sec--;				time_state = TIME_OOP;			}			break;			/*			 * Delete second 23:59:59.			 */			case TIME_DEL:			if (!(time_status & STA_DEL))				time_state = TIME_OK;			else if ((tvp->tv_sec + 1) % 86400 == 0) {				tvp->tv_sec++;				time_tai--;				time_state = TIME_WAIT;			}			break;			/*			 * Insert second in progress.			 */			case TIME_OOP:			time_tai++;			time_state = TIME_WAIT;			break;			/*			 * Wait for status bits to clear.			 */			case TIME_WAIT:			if (!(time_status & (STA_INS | STA_DEL)))				time_state = TIME_OK;		}		/*		 * Compute the total time adjustment for the next second		 * in ns. The offset is reduced by a factor depending on		 * whether the PPS signal is operating. Note that the		 * value is in effect scaled by the clock frequency,		 * since the adjustment is added at each tick interrupt.		 */		ftemp = time_offset;#ifdef PPS_SYNC		if (time_status & STA_PPSTIME && time_status &		    STA_PPSSIGNAL)			L_RSHIFT(ftemp, pps_shift);		else			L_RSHIFT(ftemp, SHIFT_PLL + time_constant);#else		L_RSHIFT(ftemp, SHIFT_PLL + time_constant);#endif /* PPS_SYNC */		time_adj = ftemp;		L_SUB(time_offset, ftemp);		L_ADD(time_adj, time_freq);		L_ADDHI(time_adj, NANOSECOND);#ifdef PPS_SYNC		if (pps_valid > 0)			pps_valid--;		else			time_status &= ~STA_PPSSIGNAL;#endif /* PPS_SYNC */	}}/* * ntp_init() - initialize variables and structures * * This routine must be called after the kernel variables hz and tick * are set or changed and before the next tick interrupt. In this * particular implementation, these values are assumed set elsewhere in * the kernel. The design allows the clock frequency and tick interval * to be changed while the system is running. So, this routine should * probably be integrated with the code that does that. */voidntp_init(){	int i;	/*	 * The following variable must be initialized any time the	 * kernel variable hz is changed.	 */	time_tick = NANOSECOND / hz;	/*	 * The following variables are initialized only at startup. Only	 * those structures not cleared by the compiler need to be	 * initialized, and these only in the simulator. In the actual	 * kernel, any nonzero values here will quickly evaporate.	 */	L_CLR(time_offset);	L_CLR(time_freq);	L_LINT(time_adj, NANOSECOND);	L_CLR(time_phase);	for (i = 0; i < NCPUS; i++)		microset_flag[i] = 0;#ifdef PPS_SYNC	pps_tf[0].tv_sec = pps_tf[0].tv_nsec = 0;	pps_tf[1].tv_sec = pps_tf[1].tv_nsec = 0;	pps_tf[2].tv_sec = pps_tf[2].tv_nsec = 0;	pps_fcount = 0;	L_CLR(pps_freq);#endif /* PPS_SYNC */ }/* * hardupdate() - local clock update * * This routine is called by ntp_adjtime() to update the local clock * phase and frequency. The implementation is of an adaptive-parameter, * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new * time and frequency offset estimates for each call. If the kernel PPS * discipline code is configured (PPS_SYNC), the PPS signal itself * determines the new time offset, instead of the calling argument. * Presumably, calls to ntp_adjtime() occur only when the caller * believes the local clock is valid within some bound (+-128 ms with * NTP). If the caller's time is far different than the PPS time, an * argument will ensue, and it's not clear who will lose. * * For uncompensated quartz crystal oscillators and nominal update * intervals less than 256 s, operation should be in phase-lock mode, * where the loop is disciplined to phase. For update intervals greater * than 1024 s, operation should be in frequency-lock mode, where the * loop is disciplined to frequency. Between 256 s and 1024 s, the mode * is selected by the STA_MODE status bit. */voidhardupdate(tvp, offset)#ifdef NTP_NANO	struct timespec *tvp;	/* pointer to nanosecond clock */#else	struct timeval *tvp;	/* pointer to microsecond clock */#endif /* NTP_NANO */	long offset;		/* clock offset (ns) */{	long mtemp;	l_fp ftemp;	/*	 * Select how the phase is to be controlled and from which	 * source. If the PPS signal is present and enabled to	 * discipline the time, the PPS offset is used; otherwise, the	 * argument offset is used.	 */	if (!(time_status & STA_PLL))		return;	if (!(time_status & STA_PPSTIME && time_status &	    STA_PPSSIGNAL)) {		if (offset > MAXPHASE)			time_monitor = MAXPHASE;		else if (offset < -MAXPHASE)			time_monitor = -MAXPHASE;		else			time_monitor = offset;		L_LINT(time_offset, time_monitor);	}	/*	 * Select how the frequency is to be controlled and in which	 * mode (PLL or FLL). If the PPS signal is present and enabled	 * to discipline the frequency, the PPS frequency is used;	 * otherwise, the argument offset is used to compute it.	 */	if (time_status & STA_PPSFREQ && time_status & STA_PPSSIGNAL) {		time_reftime = tvp->tv_sec;		return;	}	if (time_status & STA_FREQHOLD || time_reftime == 0)		time_reftime = tvp->tv_sec;	mtemp = tvp->tv_sec - time_reftime;	L_LINT(ftemp, time_monitor);	L_RSHIFT(ftemp, (SHIFT_PLL + 2 + time_constant) << 1);	L_MPY(ftemp, mtemp);	L_ADD(time_freq, ftemp);	time_status &= ~STA_MODE;	if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp >	    MAXSEC)) {		L_LINT(ftemp, (time_monitor << 4) / mtemp);		L_RSHIFT(ftemp, SHIFT_FLL + 4);		L_ADD(time_freq, ftemp);		time_status |= STA_MODE;	}	time_reftime = tvp->tv_sec;	if (L_GINT(time_freq) > MAXFREQ)		L_LINT(time_freq, MAXFREQ);	else if (L_GINT(time_freq) < -MAXFREQ)		L_LINT(time_freq, -MAXFREQ);}#ifdef PPS_SYNC/* * hardpps() - discipline CPU clock oscillator to external PPS signal * * This routine is called at each PPS interrupt in order to discipline * the CPU clock oscillator to the PPS signal. There are two independent * first-order feedback loops, one for the phase, the other for the * frequency. The phase loop measures and grooms the PPS phase offset * and leaves it in a handy spot for the seconds overflow routine. The * frequency loop averages successive PPS phase differences and * calculates the PPS frequency offset, which is also processed by the * seconds overflow routine. The code requires the caller to capture the * time and architecture-dependent hardware counter values in * nanoseconds at the on-time PPS signal transition. * * Note that, on some Unix systems this routine runs at an interrupt * priority level higher than the timer interrupt routine hardclock(). * Therefore, the variables used are distinct from the hardclock() * variables, except for the actual time and frequency variables, which * are determined by this routine and updated atomically. */voidhardpps(tsp, nsec)	struct timespec *tsp;	/* time at PPS */	long nsec;		/* hardware counter at PPS */{	long u_sec, u_nsec, v_nsec; /* temps */	l_fp ftemp;	/*	 * The signal is first processed by a range gate and frequency	 * discriminator. The range gate rejects noise spikes outside	 * the range +-500 us. The frequency discriminator rejects input	 * signals with apparent frequency outside the range 1 +-500	 * PPM. If two hits occur in the same second, we ignore the	 * later hit; if not and a hit occurs outside the range gate,	 * keep the later hit for later comparison, but do not process	 * it.	 */	time_tick = NANOSECOND / hz;	time_status |= STA_PPSSIGNAL | STA_PPSJITTER;	time_status &= ~(STA_PPSWANDER | STA_PPSERROR);	pps_valid = PPS_VALID;	u_sec = tsp->tv_sec;	u_nsec = tsp->tv_nsec;	if (u_nsec >= (NANOSECOND >> 1)) {		u_nsec -= NANOSECOND;		u_sec++;	}	v_nsec = u_nsec - pps_tf[0].tv_nsec;	if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND -	    MAXFREQ)		return;	pps_tf[2] = pps_tf[1];	pps_tf[1] = pps_tf[0];	pps_tf[0].tv_sec = u_sec;	pps_tf[0].tv_nsec = u_nsec;	/*	 * Compute the difference between the current and previous	 * counter values. If the difference exceeds 0.5 s, assume it	 * has wrapped around, so correct 1.0 s. If the result exceeds	 * the tick interval, the sample point has crossed a tick	 * boundary during the last second, so correct the tick. Very	 * intricate.	 */	u_nsec = nsec - pps_lastcount;	pps_lastcount = nsec;	if (u_nsec > (NANOSECOND >> 1))		u_nsec -= NANOSECOND;	else if (u_nsec < -(NANOSECOND >> 1))		u_nsec += NANOSECOND;	if (u_nsec > (time_tick >> 1))		u_nsec -= time_tick;	else if (u_nsec < -(time_tick >> 1))		u_nsec += time_tick;	pps_fcount += u_nsec;	if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)		return;	time_status &= ~STA_PPSJITTER;	/*	 * A three-stage median filter is used to help denoise the PPS	 * time. The median sample becomes the time offset estimate; the	 * difference between the other two samples becomes the time	 * dispersion (jitter) estimate.	 */	if (pps_tf[0].tv_nsec > pps_tf[1].tv_nsec) {		if (pps_tf[1].tv_nsec > pps_tf[2].tv_nsec) {			v_nsec = pps_tf[1].tv_nsec;	/* 0 1 2 */			u_nsec = pps_tf[0].tv_nsec - pps_tf[2].tv_nsec;		} else if (pps_tf[2].tv_nsec > pps_tf[0].tv_nsec) {			v_nsec = pps_tf[0].tv_nsec;	/* 2 0 1 */			u_nsec = pps_tf[2].tv_nsec - pps_tf[1].tv_nsec;		} else {			v_nsec = pps_tf[2].tv_nsec;	/* 0 2 1 */			u_nsec = pps_tf[0].tv_nsec - pps_tf[1].tv_nsec;		}	} else {		if (pps_tf[1].tv_nsec < pps_tf[2].tv_nsec) {			v_nsec = pps_tf[1].tv_nsec;	/* 2 1 0 */			u_nsec = pps_tf[2].tv_nsec - pps_tf[0].tv_nsec;		} else if (pps_tf[2].tv_nsec < pps_tf[0].tv_nsec) {			v_nsec = pps_tf[0].tv_nsec;	/* 1 0 2 */			u_nsec = pps_tf[1].tv_nsec - pps_tf[2].tv_nsec;		} else {			v_nsec = pps_tf[2].tv_nsec;	/* 1 2 0 */			u_nsec = pps_tf[1].tv_nsec - pps_tf[0].tv_nsec;		}	}	/*	 * Nominal jitter is due to PPS signal noise and interrupt	 * latency. If it exceeds the popcorn threshold, the sample is	 * discarded. otherwise, if so enabled, the time offset is	 * updated. We can tolerate a modest loss of data here without	 * much degrading time accuracy.	 */	if (u_nsec > (pps_jitter << PPS_POPCORN)) {		time_status |= STA_PPSJITTER;		pps_jitcnt++;	} else if (time_status & STA_PPSTIME) {		time_monitor = -v_nsec;		L_LINT(time_offset, time_monitor);	}	pps_jitter += (u_nsec - pps_jitter) >> PPS_FAVG;	u_sec = pps_tf[0].tv_sec - pps_lastsec;	if (u_sec < (1 << pps_shift))		return;	/*	 * At the end of the calibration interval the difference between	 * the first and last counter values becomes the scaled	 * frequency. It will later be divided by the length of the	 * interval to determine the frequency update. If the frequency	 * exceeds a sanity threshold, or if the actual calibration	 * interval is not equal to the expected length, the data are	 * discarded. We can tolerate a modest loss of data here without	 * much degrading frequency accuracy.	 */	pps_calcnt++;	v_nsec = -pps_fcount;	pps_lastsec = pps_tf[0].tv_sec;	pps_fcount = 0;	u_nsec = MAXFREQ << pps_shift;	if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 <<	    pps_shift)) {		time_status |= STA_PPSERROR;		pps_errcnt++;		return;	}	/*	 * Here the raw frequency offset and wander (stability) is	 * calculated. If the wander is less than the wander threshold	 * for four consecutive averaging intervals, the interval is	 * doubled; if it is greater than the threshold for four	 * consecutive intervals, the interval is halved. The scaled	 * frequency offset is converted to frequency offset. The	 * stability metric is calculated as the average of recent	 * frequency changes, but is used only for performance	 * monitoring.	 */	L_LINT(ftemp, v_nsec);	L_RSHIFT(ftemp, pps_shift);	L_SUB(ftemp, pps_freq);	u_nsec = L_GINT(ftemp);	if (u_nsec > PPS_MAXWANDER) {		L_LINT(ftemp, PPS_MAXWANDER);		pps_intcnt--;		time_status |= STA_PPSWANDER;		pps_stbcnt++;	} else if (u_nsec < -PPS_MAXWANDER) {		L_LINT(ftemp, -PPS_MAXWANDER);		pps_intcnt--;		time_status |= STA_PPSWANDER;		pps_stbcnt++;	} else {		pps_intcnt++;	}	if (pps_intcnt >= 4) {		pps_intcnt = 4;		if (pps_shift < pps_shiftmax) {			pps_shift++;			pps_intcnt = 0;		}	} else if (pps_intcnt <= -4) {		pps_intcnt = -4;		if (pps_shift > PPS_FAVG) {			pps_shift--;			pps_intcnt = 0;		}	}	if (u_nsec < 0)		u_nsec = -u_nsec;	pps_stabil += (u_nsec * SCALE_PPM - pps_stabil) >> PPS_FAVG;	/*	 * The PPS frequency is recalculated and clamped to the maximum	 * MAXFREQ. If enabled, the system clock frequency is updated as	 * well.	 */	L_ADD(pps_freq, ftemp);	u_nsec = L_GINT(pps_freq);	if (u_nsec > MAXFREQ)		L_LINT(pps_freq, MAXFREQ);	else if (u_nsec < -MAXFREQ)		L_LINT(pps_freq, -MAXFREQ);	if (time_status & STA_PPSFREQ)		time_freq = pps_freq;}#endif /* PPS_SYNC */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -