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

📄 kern_clock.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org> * Copyright (c) 1982, 1986, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)kern_clock.c	8.5 (Berkeley) 1/21/94 * $Id: kern_clock.c,v 1.86 1998/11/29 20:31:02 phk Exp $ */#include <sys/param.h>#include <sys/systm.h>#include <sys/dkstat.h>#include <sys/callout.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/malloc.h>#include <sys/resourcevar.h>#include <sys/signalvar.h>#include <sys/timex.h>#include <sys/timepps.h>#include <vm/vm.h>#include <sys/lock.h>#include <sys/sysctl.h>#include <machine/cpu.h>#include <machine/limits.h>#ifdef OSKIT#include <oskit/dev/dev.h>#endif#ifdef GPROF#include <sys/gmon.h>#endif#if defined(SMP) && defined(BETTER_CLOCK)#include <machine/smp.h>#endif/* This is where the NTIMECOUNTER option hangs out */#include "opt_ntp.h"/* * Number of timecounters used to implement stable storage */#ifndef NTIMECOUNTER#define NTIMECOUNTER	5#endifstatic MALLOC_DEFINE(M_TIMECOUNTER, "timecounter", 	"Timecounter stable storage");static void initclocks __P((void *dummy));SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)static void tco_forward __P((int force));static void tco_setscales __P((struct timecounter *tc));static __inline unsigned tco_delta __P((struct timecounter *tc));/* Some of these don't belong here, but it's easiest to concentrate them. */#if defined(SMP) && defined(BETTER_CLOCK)long cp_time[CPUSTATES];#elsestatic long cp_time[CPUSTATES];#endiflong tk_cancc;long tk_nin;long tk_nout;long tk_rawcc;time_t time_second;/* * Which update policy to use. *   0 - every tick, bad hardware may fail with "calcru negative..." *   1 - more resistent to the above hardware, but less efficient. */static int tco_method;/* * Implement a dummy timecounter which we can use until we get a real one * in the air.  This allows the console and other early stuff to use * timeservices. */static unsigned dummy_get_timecount(struct timecounter *tc){	static unsigned now;	return (++now);}static struct timecounter dummy_timecounter = {	dummy_get_timecount,	0,	~0u,	1000000,	"dummy"};struct timecounter *timecounter = &dummy_timecounter;/* * Clock handling routines. * * This code is written to operate with two timers that run independently of * each other. * * The main timer, running hz times per second, is used to trigger interval * timers, timeouts and rescheduling as needed. * * The second timer handles kernel and user profiling, * and does resource use estimation.  If the second timer is programmable, * it is randomized to avoid aliasing between the two clocks.  For example, * the randomization prevents an adversary from always giving up the cpu * just before its quantum expires.  Otherwise, it would never accumulate * cpu ticks.  The mean frequency of the second timer is stathz. * * If no second timer exists, stathz will be zero; in this case we drive * profiling and statistics off the main clock.  This WILL NOT be accurate; * do not do it unless absolutely necessary. * * The statistics clock may (or may not) be run at a higher rate while * profiling.  This profile clock runs at profhz.  We require that profhz * be an integral multiple of stathz. * * If the statistics clock is running fast, it must be divided by the ratio * profhz/stathz for statistics.  (For profiling, every tick counts.) * * Time-of-day is maintained using a "timecounter", which may or may * not be related to the hardware generating the above mentioned * interrupts. */int	stathz;int	profhz;static int profprocs;int	ticks;static int psdiv, pscnt;		/* prof => stat divider */int	psratio;			/* ratio: prof / stat *//* * Initialize clock frequencies and start both clocks running. *//* ARGSUSED*/static voidinitclocks(dummy)	void *dummy;{	register int i;	/*	 * Set divisors to 1 (normal case) and let the machine-specific	 * code do its bit.	 */	psdiv = pscnt = 1;#ifndef OSKIT	cpu_initclocks();#endif	/*	 * Compute profhz/stathz, and fix profhz if needed.	 */	i = stathz ? stathz : hz;	if (profhz == 0)		profhz = i;	psratio = profhz / i;}/* * The real-time timer, interrupting hz times per second. */void#ifdef OSKITbsd_hardclock(void)#elsehardclock(frame)	register struct clockframe *frame;#endif{#ifndef OSKIT	register struct proc *p;#else	unsigned cpl;	save_cpl(&cpl);	/*	 * Timer interrupt handler is always entered with ints off,	 * sync BSDs notion of the CPL with that.	 */	osenv_assert(osenv_intr_enabled() == 0);	splhigh();#endif#ifndef OSKIT	p = curproc;	if (p) {		register struct pstats *pstats;		/*		 * Run current process's virtual and profile time, as needed.		 */		pstats = p->p_stats;		if (CLKF_USERMODE(frame) &&		    timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&		    itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0)			psignal(p, SIGVTALRM);		if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) &&		    itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0)			psignal(p, SIGPROF);	}#if defined(SMP) && defined(BETTER_CLOCK)	forward_hardclock(pscnt);#endif	/*	 * If no separate statistics clock is available, run it from here.	 */	if (stathz == 0)		statclock(frame);#endif	tco_forward(0);	ticks++;	/*	 * Process callouts at a very low cpu priority, so we don't keep the	 * relatively high clock interrupt priority any longer than necessary.	 */	if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {#ifndef OSKIT		if (CLKF_BASEPRI(frame)) {			/*			 * Save the overhead of a software interrupt;			 * it will happen as soon as we return, so do it now.			 */			(void)splsoftclock();			softclock();		} else#endif			setsoftclock();	} else if (softticks + 1 == ticks)		++softticks;#ifdef OSKIT	osenv_assert(osenv_intr_enabled() == 0);	restore_cpl(cpl);#endif}/* * Compute number of ticks in the specified amount of time. */inttvtohz(tv)	struct timeval *tv;{	register unsigned long ticks;	register long sec, usec;	/*	 * If the number of usecs in the whole seconds part of the time	 * difference fits in a long, then the total number of usecs will	 * fit in an unsigned long.  Compute the total and convert it to	 * ticks, rounding up and adding 1 to allow for the current tick	 * to expire.  Rounding also depends on unsigned long arithmetic	 * to avoid overflow.	 *	 * Otherwise, if the number of ticks in the whole seconds part of	 * the time difference fits in a long, then convert the parts to	 * ticks separately and add, using similar rounding methods and	 * overflow avoidance.  This method would work in the previous	 * case but it is slightly slower and assumes that hz is integral.	 *	 * Otherwise, round the time difference down to the maximum	 * representable value.	 *	 * If ints have 32 bits, then the maximum value for any timeout in	 * 10ms ticks is 248 days.	 */	sec = tv->tv_sec;	usec = tv->tv_usec;	if (usec < 0) {		sec--;		usec += 1000000;	}	if (sec < 0) {#ifdef DIAGNOSTIC		if (usec > 0) {			sec++;			usec -= 1000000;		}		printf("tvotohz: negative time difference %ld sec %ld usec\n",		       sec, usec);#endif		ticks = 1;	} else if (sec <= LONG_MAX / 1000000)		ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))			/ tick + 1;	else if (sec <= LONG_MAX / hz)		ticks = sec * hz			+ ((unsigned long)usec + (tick - 1)) / tick + 1;	else		ticks = LONG_MAX;	if (ticks > INT_MAX)		ticks = INT_MAX;	return ((int)ticks);}#ifndef OSKIT/* * Start profiling on a process. * * Kernel profiling passes proc0 which never exits and hence * keeps the profile clock running constantly. */voidstartprofclock(p)	register struct proc *p;{	int s;	if ((p->p_flag & P_PROFIL) == 0) {		p->p_flag |= P_PROFIL;		if (++profprocs == 1 && stathz != 0) {			s = splstatclock();			psdiv = pscnt = psratio;			setstatclockrate(profhz);			splx(s);		}	}}/* * Stop profiling on a process. */voidstopprofclock(p)	register struct proc *p;{	int s;	if (p->p_flag & P_PROFIL) {		p->p_flag &= ~P_PROFIL;		if (--profprocs == 0 && stathz != 0) {			s = splstatclock();			psdiv = pscnt = 1;			setstatclockrate(stathz);			splx(s);		}	}}/* * Statistics clock.  Grab profile sample, and if divider reaches 0, * do process and kernel statistics. */voidstatclock(frame)	register struct clockframe *frame;{#ifdef GPROF	register struct gmonparam *g;	int i;#endif	register struct proc *p;	struct pstats *pstats;	long rss;	struct rusage *ru;	struct vmspace *vm;	if (curproc != NULL && CLKF_USERMODE(frame)) {		p = curproc;		if (p->p_flag & P_PROFIL)			addupc_intr(p, CLKF_PC(frame), 1);#if defined(SMP) && defined(BETTER_CLOCK)		if (stathz != 0)			forward_statclock(pscnt);#endif		if (--pscnt > 0)			return;		/*		 * Came from user mode; CPU was in user state.		 * If this process is being profiled record the tick.		 */		p->p_uticks++;		if (p->p_nice > NZERO)			cp_time[CP_NICE]++;		else			cp_time[CP_USER]++;	} else {#ifdef GPROF		/*		 * Kernel statistics are just like addupc_intr, only easier.		 */		g = &_gmonparam;		if (g->state == GMON_PROF_ON) {			i = CLKF_PC(frame) - g->lowpc;			if (i < g->textsize) {				i /= HISTFRACTION * sizeof(*g->kcount);				g->kcount[i]++;			}		}#endif#if defined(SMP) && defined(BETTER_CLOCK)		if (stathz != 0)			forward_statclock(pscnt);#endif		if (--pscnt > 0)			return;		/*		 * Came from kernel mode, so we were:		 * - handling an interrupt,		 * - doing syscall or trap work on behalf of the current		 *   user process, or		 * - spinning in the idle loop.		 * Whichever it is, charge the time as appropriate.		 * Note that we charge interrupts to the current process,		 * regardless of whether they are ``for'' that process,		 * so that we know how much of its real time was spent		 * in ``non-process'' (i.e., interrupt) work.		 */		p = curproc;		if (CLKF_INTR(frame)) {			if (p != NULL)				p->p_iticks++;			cp_time[CP_INTR]++;		} else if (p != NULL) {			p->p_sticks++;			cp_time[CP_SYS]++;		} else			cp_time[CP_IDLE]++;	}	pscnt = psdiv;	/*	 * We maintain statistics shown by user-level statistics	 * programs:  the amount of time in each cpu state.	 */	/*	 * We adjust the priority of the current process.  The priority of	 * a process gets worse as it accumulates CPU time.  The cpu usage	 * estimator (p_estcpu) is increased here.  The formula for computing	 * priorities (in kern_synch.c) will compute a different value each	 * time p_estcpu increases by 4.  The cpu usage estimator ramps up	 * quite quickly when the process is running (linearly), and decays	 * away exponentially, at a rate which is proportionally slower when	 * the system is busy.  The basic principal is that the system will	 * 90% forget that the process used a lot of CPU time in 5 * loadav	 * seconds.  This causes the system to favor processes which haven't	 * run much recently, and to round-robin among other processes.	 */	if (p != NULL) {		p->p_cpticks++;		if (++p->p_estcpu == 0)			p->p_estcpu--;		if ((p->p_estcpu & 3) == 0) {			resetpriority(p);			if (p->p_priority >= PUSER)				p->p_priority = p->p_usrpri;		}		/* Update resource usage integrals and maximums. */		if ((pstats = p->p_stats) != NULL &&		    (ru = &pstats->p_ru) != NULL &&		    (vm = p->p_vmspace) != NULL) {			ru->ru_ixrss += vm->vm_tsize * PAGE_SIZE / 1024;			ru->ru_idrss += vm->vm_dsize * PAGE_SIZE / 1024;			ru->ru_isrss += vm->vm_ssize * PAGE_SIZE / 1024;			rss = vm->vm_pmap.pm_stats.resident_count *			      PAGE_SIZE / 1024;			if (ru->ru_maxrss < rss)				ru->ru_maxrss = rss;        	}	}}/* * Return information about system clocks. */static intsysctl_kern_clockrate SYSCTL_HANDLER_ARGS{	struct clockinfo clkinfo;	/*	 * Construct clockinfo structure.

⌨️ 快捷键说明

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