Annotation of src/sys/kern/kern_time.c, Revision 1.19
1.19 ! christos 1: /* $NetBSD: kern_time.c,v 1.18 1996/02/09 18:59:53 christos Exp $ */
1.9 cgd 2:
1.1 cgd 3: /*
1.8 cgd 4: * Copyright (c) 1982, 1986, 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
1.9 cgd 35: * @(#)kern_time.c 8.1 (Berkeley) 6/10/93
1.1 cgd 36: */
37:
1.5 mycroft 38: #include <sys/param.h>
39: #include <sys/resourcevar.h>
40: #include <sys/kernel.h>
1.8 cgd 41: #include <sys/systm.h>
1.5 mycroft 42: #include <sys/proc.h>
1.8 cgd 43: #include <sys/vnode.h>
1.17 christos 44: #include <sys/signalvar.h>
1.1 cgd 45:
1.11 cgd 46: #include <sys/mount.h>
47: #include <sys/syscallargs.h>
1.19 ! christos 48:
! 49: #if defined(NFSCLIENT) || defined(NFSSERVER)
! 50: #include <nfs/nfs_var.h>
! 51: #endif
1.17 christos 52:
1.5 mycroft 53: #include <machine/cpu.h>
1.1 cgd 54:
55: /*
56: * Time of day and interval timer support.
57: *
58: * These routines provide the kernel entry points to get and set
59: * the time-of-day and per-process interval timers. Subroutines
60: * here provide support for adding and subtracting timeval structures
61: * and decrementing interval timers, optionally reloading the interval
62: * timers when they expire.
63: */
64:
65: /* ARGSUSED */
1.3 andrew 66: int
1.16 mycroft 67: sys_gettimeofday(p, v, retval)
1.1 cgd 68: struct proc *p;
1.15 thorpej 69: void *v;
70: register_t *retval;
71: {
1.16 mycroft 72: register struct sys_gettimeofday_args /* {
1.11 cgd 73: syscallarg(struct timeval *) tp;
74: syscallarg(struct timezone *) tzp;
1.15 thorpej 75: } */ *uap = v;
1.1 cgd 76: struct timeval atv;
77: int error = 0;
78:
1.11 cgd 79: if (SCARG(uap, tp)) {
1.1 cgd 80: microtime(&atv);
1.17 christos 81: error = copyout((caddr_t)&atv, (caddr_t)SCARG(uap, tp),
82: sizeof (atv));
83: if (error)
1.1 cgd 84: return (error);
85: }
1.11 cgd 86: if (SCARG(uap, tzp))
87: error = copyout((caddr_t)&tz, (caddr_t)SCARG(uap, tzp),
1.1 cgd 88: sizeof (tz));
89: return (error);
90: }
91:
92: /* ARGSUSED */
1.3 andrew 93: int
1.16 mycroft 94: sys_settimeofday(p, v, retval)
1.1 cgd 95: struct proc *p;
1.15 thorpej 96: void *v;
97: register_t *retval;
98: {
1.16 mycroft 99: struct sys_settimeofday_args /* {
1.11 cgd 100: syscallarg(struct timeval *) tv;
101: syscallarg(struct timezone *) tzp;
1.15 thorpej 102: } */ *uap = v;
1.8 cgd 103: struct timeval atv, delta;
1.1 cgd 104: struct timezone atz;
105: int error, s;
106:
1.17 christos 107: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1.1 cgd 108: return (error);
1.8 cgd 109: /* Verify all parameters before changing time. */
1.11 cgd 110: if (SCARG(uap, tv) && (error = copyin((caddr_t)SCARG(uap, tv),
111: (caddr_t)&atv, sizeof(atv))))
1.8 cgd 112: return (error);
1.11 cgd 113: if (SCARG(uap, tzp) && (error = copyin((caddr_t)SCARG(uap, tzp),
114: (caddr_t)&atz, sizeof(atz))))
1.8 cgd 115: return (error);
1.11 cgd 116: if (SCARG(uap, tv)) {
1.1 cgd 117: /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1.8 cgd 118: s = splclock();
1.14 mycroft 119: timersub(&atv, &time, &delta);
1.8 cgd 120: time = atv;
121: (void) splsoftclock();
1.14 mycroft 122: timeradd(&boottime, &delta, &boottime);
123: timeradd(&runtime, &delta, &runtime);
1.13 mycroft 124: # if defined(NFSCLIENT) || defined(NFSSERVER)
125: lease_updatetime(delta.tv_sec);
126: # endif
1.8 cgd 127: splx(s);
1.1 cgd 128: resettodr();
129: }
1.11 cgd 130: if (SCARG(uap, tzp))
1.1 cgd 131: tz = atz;
1.8 cgd 132: return (0);
1.1 cgd 133: }
134:
135: int tickdelta; /* current clock skew, us. per tick */
136: long timedelta; /* unapplied time correction, us. */
137: long bigadj = 1000000; /* use 10x skew above bigadj us. */
138:
139: /* ARGSUSED */
1.3 andrew 140: int
1.16 mycroft 141: sys_adjtime(p, v, retval)
1.1 cgd 142: struct proc *p;
1.15 thorpej 143: void *v;
144: register_t *retval;
145: {
1.16 mycroft 146: register struct sys_adjtime_args /* {
1.11 cgd 147: syscallarg(struct timeval *) delta;
148: syscallarg(struct timeval *) olddelta;
1.15 thorpej 149: } */ *uap = v;
1.8 cgd 150: struct timeval atv;
151: register long ndelta, ntickdelta, odelta;
1.1 cgd 152: int s, error;
153:
1.17 christos 154: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1.1 cgd 155: return (error);
1.17 christos 156:
157: error = copyin((caddr_t)SCARG(uap, delta), (caddr_t)&atv,
158: sizeof(struct timeval));
159: if (error)
1.1 cgd 160: return (error);
1.8 cgd 161:
162: /*
163: * Compute the total correction and the rate at which to apply it.
164: * Round the adjustment down to a whole multiple of the per-tick
165: * delta, so that after some number of incremental changes in
166: * hardclock(), tickdelta will become zero, lest the correction
167: * overshoot and start taking us away from the desired final time.
168: */
1.1 cgd 169: ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
1.8 cgd 170: if (ndelta > bigadj)
171: ntickdelta = 10 * tickadj;
172: else
173: ntickdelta = tickadj;
174: if (ndelta % ntickdelta)
175: ndelta = ndelta / ntickdelta * ntickdelta;
176:
177: /*
178: * To make hardclock()'s job easier, make the per-tick delta negative
179: * if we want time to run slower; then hardclock can simply compute
180: * tick + tickdelta, and subtract tickdelta from timedelta.
181: */
182: if (ndelta < 0)
183: ntickdelta = -ntickdelta;
1.1 cgd 184: s = splclock();
1.8 cgd 185: odelta = timedelta;
1.1 cgd 186: timedelta = ndelta;
1.8 cgd 187: tickdelta = ntickdelta;
1.1 cgd 188: splx(s);
189:
1.11 cgd 190: if (SCARG(uap, olddelta)) {
1.8 cgd 191: atv.tv_sec = odelta / 1000000;
192: atv.tv_usec = odelta % 1000000;
1.11 cgd 193: (void) copyout((caddr_t)&atv, (caddr_t)SCARG(uap, olddelta),
1.8 cgd 194: sizeof(struct timeval));
195: }
1.1 cgd 196: return (0);
197: }
198:
199: /*
200: * Get value of an interval timer. The process virtual and
201: * profiling virtual time timers are kept in the p_stats area, since
202: * they can be swapped out. These are kept internally in the
203: * way they are specified externally: in time until they expire.
204: *
205: * The real time interval timer is kept in the process table slot
206: * for the process, and its value (it_value) is kept as an
207: * absolute time rather than as a delta, so that it is easy to keep
208: * periodic real-time signals from drifting.
209: *
210: * Virtual time timers are processed in the hardclock() routine of
211: * kern_clock.c. The real time timer is processed by a timeout
212: * routine, called from the softclock() routine. Since a callout
213: * may be delayed in real time due to interrupt processing in the system,
214: * it is possible for the real time timeout routine (realitexpire, given below),
215: * to be delayed in real time past when it is supposed to occur. It
216: * does not suffice, therefore, to reload the real timer .it_value from the
217: * real time timers .it_interval. Rather, we compute the next time in
218: * absolute time the timer should go off.
219: */
220: /* ARGSUSED */
1.3 andrew 221: int
1.16 mycroft 222: sys_getitimer(p, v, retval)
1.1 cgd 223: struct proc *p;
1.15 thorpej 224: void *v;
225: register_t *retval;
226: {
1.16 mycroft 227: register struct sys_getitimer_args /* {
1.11 cgd 228: syscallarg(u_int) which;
229: syscallarg(struct itimerval *) itv;
1.15 thorpej 230: } */ *uap = v;
1.1 cgd 231: struct itimerval aitv;
232: int s;
233:
1.11 cgd 234: if (SCARG(uap, which) > ITIMER_PROF)
1.1 cgd 235: return (EINVAL);
236: s = splclock();
1.11 cgd 237: if (SCARG(uap, which) == ITIMER_REAL) {
1.1 cgd 238: /*
1.12 mycroft 239: * Convert from absolute to relative time in .it_value
1.1 cgd 240: * part of real time timer. If time for real time timer
241: * has passed return 0, else return difference between
242: * current time and time for the timer to go off.
243: */
244: aitv = p->p_realtimer;
245: if (timerisset(&aitv.it_value))
246: if (timercmp(&aitv.it_value, &time, <))
247: timerclear(&aitv.it_value);
248: else
1.14 mycroft 249: timersub(&aitv.it_value, &time, &aitv.it_value);
1.1 cgd 250: } else
1.11 cgd 251: aitv = p->p_stats->p_timer[SCARG(uap, which)];
1.1 cgd 252: splx(s);
1.11 cgd 253: return (copyout((caddr_t)&aitv, (caddr_t)SCARG(uap, itv),
1.1 cgd 254: sizeof (struct itimerval)));
255: }
256:
257: /* ARGSUSED */
1.3 andrew 258: int
1.16 mycroft 259: sys_setitimer(p, v, retval)
1.1 cgd 260: struct proc *p;
1.17 christos 261: register void *v;
1.15 thorpej 262: register_t *retval;
263: {
1.16 mycroft 264: register struct sys_setitimer_args /* {
1.11 cgd 265: syscallarg(u_int) which;
266: syscallarg(struct itimerval *) itv;
267: syscallarg(struct itimerval *) oitv;
1.15 thorpej 268: } */ *uap = v;
1.1 cgd 269: struct itimerval aitv;
270: register struct itimerval *itvp;
271: int s, error;
272:
1.11 cgd 273: if (SCARG(uap, which) > ITIMER_PROF)
1.1 cgd 274: return (EINVAL);
1.11 cgd 275: itvp = SCARG(uap, itv);
1.1 cgd 276: if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
277: sizeof(struct itimerval))))
278: return (error);
1.11 cgd 279: if ((SCARG(uap, itv) = SCARG(uap, oitv)) &&
1.16 mycroft 280: (error = sys_getitimer(p, uap, retval)))
1.1 cgd 281: return (error);
282: if (itvp == 0)
283: return (0);
284: if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
285: return (EINVAL);
286: s = splclock();
1.11 cgd 287: if (SCARG(uap, which) == ITIMER_REAL) {
1.7 mycroft 288: untimeout(realitexpire, p);
1.1 cgd 289: if (timerisset(&aitv.it_value)) {
1.14 mycroft 290: timeradd(&aitv.it_value, &time, &aitv.it_value);
1.7 mycroft 291: timeout(realitexpire, p, hzto(&aitv.it_value));
1.1 cgd 292: }
293: p->p_realtimer = aitv;
294: } else
1.11 cgd 295: p->p_stats->p_timer[SCARG(uap, which)] = aitv;
1.1 cgd 296: splx(s);
297: return (0);
298: }
299:
300: /*
301: * Real interval timer expired:
302: * send process whose timer expired an alarm signal.
303: * If time is not set up to reload, then just return.
304: * Else compute next time timer should go off which is > current time.
305: * This is where delay in processing this timeout causes multiple
306: * SIGALRM calls to be compressed into one.
307: */
1.3 andrew 308: void
1.6 cgd 309: realitexpire(arg)
310: void *arg;
311: {
1.1 cgd 312: register struct proc *p;
313: int s;
314:
1.6 cgd 315: p = (struct proc *)arg;
1.1 cgd 316: psignal(p, SIGALRM);
317: if (!timerisset(&p->p_realtimer.it_interval)) {
318: timerclear(&p->p_realtimer.it_value);
319: return;
320: }
321: for (;;) {
322: s = splclock();
1.14 mycroft 323: timeradd(&p->p_realtimer.it_value,
324: &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
1.1 cgd 325: if (timercmp(&p->p_realtimer.it_value, &time, >)) {
1.7 mycroft 326: timeout(realitexpire, p,
1.1 cgd 327: hzto(&p->p_realtimer.it_value));
328: splx(s);
329: return;
330: }
331: splx(s);
332: }
333: }
334:
335: /*
336: * Check that a proposed value to load into the .it_value or
337: * .it_interval part of an interval timer is acceptable, and
338: * fix it to have at least minimal value (i.e. if it is less
339: * than the resolution of the clock, round it up.)
340: */
1.3 andrew 341: int
1.1 cgd 342: itimerfix(tv)
343: struct timeval *tv;
344: {
345:
346: if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
347: tv->tv_usec < 0 || tv->tv_usec >= 1000000)
348: return (EINVAL);
349: if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
350: tv->tv_usec = tick;
351: return (0);
352: }
353:
354: /*
355: * Decrement an interval timer by a specified number
356: * of microseconds, which must be less than a second,
357: * i.e. < 1000000. If the timer expires, then reload
358: * it. In this case, carry over (usec - old value) to
1.8 cgd 359: * reduce the value reloaded into the timer so that
1.1 cgd 360: * the timer does not drift. This routine assumes
361: * that it is called in a context where the timers
362: * on which it is operating cannot change in value.
363: */
1.3 andrew 364: int
1.1 cgd 365: itimerdecr(itp, usec)
366: register struct itimerval *itp;
367: int usec;
368: {
369:
370: if (itp->it_value.tv_usec < usec) {
371: if (itp->it_value.tv_sec == 0) {
372: /* expired, and already in next interval */
373: usec -= itp->it_value.tv_usec;
374: goto expire;
375: }
376: itp->it_value.tv_usec += 1000000;
377: itp->it_value.tv_sec--;
378: }
379: itp->it_value.tv_usec -= usec;
380: usec = 0;
381: if (timerisset(&itp->it_value))
382: return (1);
383: /* expired, exactly at end of interval */
384: expire:
385: if (timerisset(&itp->it_interval)) {
386: itp->it_value = itp->it_interval;
387: itp->it_value.tv_usec -= usec;
388: if (itp->it_value.tv_usec < 0) {
389: itp->it_value.tv_usec += 1000000;
390: itp->it_value.tv_sec--;
391: }
392: } else
393: itp->it_value.tv_usec = 0; /* sec is already 0 */
394: return (0);
395: }
CVSweb <webmaster@jp.NetBSD.org>