Annotation of src/sys/kern/kern_time.c, Revision 1.11
1.11 ! cgd 1: /* $NetBSD: kern_time.c,v 1.10 1994/09/18 21:49:07 mycroft 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.1 cgd 44:
1.11 ! cgd 45: #include <sys/mount.h>
! 46: #include <sys/syscallargs.h>
! 47:
1.5 mycroft 48: #include <machine/cpu.h>
1.1 cgd 49:
50: /*
51: * Time of day and interval timer support.
52: *
53: * These routines provide the kernel entry points to get and set
54: * the time-of-day and per-process interval timers. Subroutines
55: * here provide support for adding and subtracting timeval structures
56: * and decrementing interval timers, optionally reloading the interval
57: * timers when they expire.
58: */
59:
60: /* ARGSUSED */
1.3 andrew 61: int
1.1 cgd 62: gettimeofday(p, uap, retval)
63: struct proc *p;
1.11 ! cgd 64: register struct gettimeofday_args /* {
! 65: syscallarg(struct timeval *) tp;
! 66: syscallarg(struct timezone *) tzp;
! 67: } */ *uap;
! 68: register_t *retval;
1.1 cgd 69: {
70: struct timeval atv;
71: int error = 0;
72:
1.11 ! cgd 73: if (SCARG(uap, tp)) {
1.1 cgd 74: microtime(&atv);
1.11 ! cgd 75: if (error = copyout((caddr_t)&atv, (caddr_t)SCARG(uap, tp),
1.1 cgd 76: sizeof (atv)))
77: return (error);
78: }
1.11 ! cgd 79: if (SCARG(uap, tzp))
! 80: error = copyout((caddr_t)&tz, (caddr_t)SCARG(uap, tzp),
1.1 cgd 81: sizeof (tz));
82: return (error);
83: }
84:
85: /* ARGSUSED */
1.3 andrew 86: int
1.1 cgd 87: settimeofday(p, uap, retval)
88: struct proc *p;
1.11 ! cgd 89: struct settimeofday_args /* {
! 90: syscallarg(struct timeval *) tv;
! 91: syscallarg(struct timezone *) tzp;
! 92: } */ *uap;
! 93: register_t *retval;
1.1 cgd 94: {
1.8 cgd 95: struct timeval atv, delta;
1.1 cgd 96: struct timezone atz;
97: int error, s;
98:
99: if (error = suser(p->p_ucred, &p->p_acflag))
100: return (error);
1.8 cgd 101: /* Verify all parameters before changing time. */
1.11 ! cgd 102: if (SCARG(uap, tv) && (error = copyin((caddr_t)SCARG(uap, tv),
! 103: (caddr_t)&atv, sizeof(atv))))
1.8 cgd 104: return (error);
1.11 ! cgd 105: if (SCARG(uap, tzp) && (error = copyin((caddr_t)SCARG(uap, tzp),
! 106: (caddr_t)&atz, sizeof(atz))))
1.8 cgd 107: return (error);
1.11 ! cgd 108: if (SCARG(uap, tv)) {
1.1 cgd 109: /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1.8 cgd 110: s = splclock();
111: /* nb. delta.tv_usec may be < 0, but this is OK here */
112: delta.tv_sec = atv.tv_sec - time.tv_sec;
113: delta.tv_usec = atv.tv_usec - time.tv_usec;
114: time = atv;
115: (void) splsoftclock();
116: timevaladd(&boottime, &delta);
117: timevalfix(&boottime);
118: timevaladd(&runtime, &delta);
119: timevalfix(&runtime);
120: LEASE_UPDATETIME(delta.tv_sec);
121: splx(s);
1.1 cgd 122: resettodr();
123: }
1.11 ! cgd 124: if (SCARG(uap, tzp))
1.1 cgd 125: tz = atz;
1.8 cgd 126: return (0);
1.1 cgd 127: }
128:
129: int tickdelta; /* current clock skew, us. per tick */
130: long timedelta; /* unapplied time correction, us. */
131: long bigadj = 1000000; /* use 10x skew above bigadj us. */
132:
133: /* ARGSUSED */
1.3 andrew 134: int
1.1 cgd 135: adjtime(p, uap, retval)
136: struct proc *p;
1.11 ! cgd 137: register struct adjtime_args /* {
! 138: syscallarg(struct timeval *) delta;
! 139: syscallarg(struct timeval *) olddelta;
! 140: } */ *uap;
! 141: register_t *retval;
1.1 cgd 142: {
1.8 cgd 143: struct timeval atv;
144: register long ndelta, ntickdelta, odelta;
1.1 cgd 145: int s, error;
146:
147: if (error = suser(p->p_ucred, &p->p_acflag))
148: return (error);
1.11 ! cgd 149: if (error = copyin((caddr_t)SCARG(uap, delta), (caddr_t)&atv,
! 150: sizeof(struct timeval)))
1.1 cgd 151: return (error);
1.8 cgd 152:
153: /*
154: * Compute the total correction and the rate at which to apply it.
155: * Round the adjustment down to a whole multiple of the per-tick
156: * delta, so that after some number of incremental changes in
157: * hardclock(), tickdelta will become zero, lest the correction
158: * overshoot and start taking us away from the desired final time.
159: */
1.1 cgd 160: ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
1.8 cgd 161: if (ndelta > bigadj)
162: ntickdelta = 10 * tickadj;
163: else
164: ntickdelta = tickadj;
165: if (ndelta % ntickdelta)
166: ndelta = ndelta / ntickdelta * ntickdelta;
167:
168: /*
169: * To make hardclock()'s job easier, make the per-tick delta negative
170: * if we want time to run slower; then hardclock can simply compute
171: * tick + tickdelta, and subtract tickdelta from timedelta.
172: */
173: if (ndelta < 0)
174: ntickdelta = -ntickdelta;
1.1 cgd 175: s = splclock();
1.8 cgd 176: odelta = timedelta;
1.1 cgd 177: timedelta = ndelta;
1.8 cgd 178: tickdelta = ntickdelta;
1.1 cgd 179: splx(s);
180:
1.11 ! cgd 181: if (SCARG(uap, olddelta)) {
1.8 cgd 182: atv.tv_sec = odelta / 1000000;
183: atv.tv_usec = odelta % 1000000;
1.11 ! cgd 184: (void) copyout((caddr_t)&atv, (caddr_t)SCARG(uap, olddelta),
1.8 cgd 185: sizeof(struct timeval));
186: }
1.1 cgd 187: return (0);
188: }
189:
190: /*
191: * Get value of an interval timer. The process virtual and
192: * profiling virtual time timers are kept in the p_stats area, since
193: * they can be swapped out. These are kept internally in the
194: * way they are specified externally: in time until they expire.
195: *
196: * The real time interval timer is kept in the process table slot
197: * for the process, and its value (it_value) is kept as an
198: * absolute time rather than as a delta, so that it is easy to keep
199: * periodic real-time signals from drifting.
200: *
201: * Virtual time timers are processed in the hardclock() routine of
202: * kern_clock.c. The real time timer is processed by a timeout
203: * routine, called from the softclock() routine. Since a callout
204: * may be delayed in real time due to interrupt processing in the system,
205: * it is possible for the real time timeout routine (realitexpire, given below),
206: * to be delayed in real time past when it is supposed to occur. It
207: * does not suffice, therefore, to reload the real timer .it_value from the
208: * real time timers .it_interval. Rather, we compute the next time in
209: * absolute time the timer should go off.
210: */
211: /* ARGSUSED */
1.3 andrew 212: int
1.1 cgd 213: getitimer(p, uap, retval)
214: struct proc *p;
1.11 ! cgd 215: register struct getitimer_args /* {
! 216: syscallarg(u_int) which;
! 217: syscallarg(struct itimerval *) itv;
! 218: } */ *uap;
! 219: register_t *retval;
1.1 cgd 220: {
221: struct itimerval aitv;
222: int s;
223:
1.11 ! cgd 224: if (SCARG(uap, which) > ITIMER_PROF)
1.1 cgd 225: return (EINVAL);
226: s = splclock();
1.11 ! cgd 227: if (SCARG(uap, which) == ITIMER_REAL) {
1.1 cgd 228: /*
229: * Convert from absoulte to relative time in .it_value
230: * part of real time timer. If time for real time timer
231: * has passed return 0, else return difference between
232: * current time and time for the timer to go off.
233: */
234: aitv = p->p_realtimer;
235: if (timerisset(&aitv.it_value))
236: if (timercmp(&aitv.it_value, &time, <))
237: timerclear(&aitv.it_value);
238: else
1.6 cgd 239: timevalsub(&aitv.it_value,
240: (struct timeval *)&time);
1.1 cgd 241: } else
1.11 ! cgd 242: aitv = p->p_stats->p_timer[SCARG(uap, which)];
1.1 cgd 243: splx(s);
1.11 ! cgd 244: return (copyout((caddr_t)&aitv, (caddr_t)SCARG(uap, itv),
1.1 cgd 245: sizeof (struct itimerval)));
246: }
247:
248: /* ARGSUSED */
1.3 andrew 249: int
1.1 cgd 250: setitimer(p, uap, retval)
251: struct proc *p;
1.11 ! cgd 252: register struct setitimer_args /* {
! 253: syscallarg(u_int) which;
! 254: syscallarg(struct itimerval *) itv;
! 255: syscallarg(struct itimerval *) oitv;
! 256: } */ *uap;
! 257: register_t *retval;
1.1 cgd 258: {
259: struct itimerval aitv;
260: register struct itimerval *itvp;
261: int s, error;
262:
1.11 ! cgd 263: if (SCARG(uap, which) > ITIMER_PROF)
1.1 cgd 264: return (EINVAL);
1.11 ! cgd 265: itvp = SCARG(uap, itv);
1.1 cgd 266: if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
267: sizeof(struct itimerval))))
268: return (error);
1.11 ! cgd 269: if ((SCARG(uap, itv) = SCARG(uap, oitv)) &&
! 270: (error = getitimer(p, uap, retval)))
1.1 cgd 271: return (error);
272: if (itvp == 0)
273: return (0);
274: if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
275: return (EINVAL);
276: s = splclock();
1.11 ! cgd 277: if (SCARG(uap, which) == ITIMER_REAL) {
1.7 mycroft 278: untimeout(realitexpire, p);
1.1 cgd 279: if (timerisset(&aitv.it_value)) {
1.6 cgd 280: timevaladd(&aitv.it_value, (struct timeval *)&time);
1.7 mycroft 281: timeout(realitexpire, p, hzto(&aitv.it_value));
1.1 cgd 282: }
283: p->p_realtimer = aitv;
284: } else
1.11 ! cgd 285: p->p_stats->p_timer[SCARG(uap, which)] = aitv;
1.1 cgd 286: splx(s);
287: return (0);
288: }
289:
290: /*
291: * Real interval timer expired:
292: * send process whose timer expired an alarm signal.
293: * If time is not set up to reload, then just return.
294: * Else compute next time timer should go off which is > current time.
295: * This is where delay in processing this timeout causes multiple
296: * SIGALRM calls to be compressed into one.
297: */
1.3 andrew 298: void
1.6 cgd 299: realitexpire(arg)
300: void *arg;
301: {
1.1 cgd 302: register struct proc *p;
303: int s;
304:
1.6 cgd 305: p = (struct proc *)arg;
1.1 cgd 306: psignal(p, SIGALRM);
307: if (!timerisset(&p->p_realtimer.it_interval)) {
308: timerclear(&p->p_realtimer.it_value);
309: return;
310: }
311: for (;;) {
312: s = splclock();
313: timevaladd(&p->p_realtimer.it_value,
314: &p->p_realtimer.it_interval);
315: if (timercmp(&p->p_realtimer.it_value, &time, >)) {
1.7 mycroft 316: timeout(realitexpire, p,
1.1 cgd 317: hzto(&p->p_realtimer.it_value));
318: splx(s);
319: return;
320: }
321: splx(s);
322: }
323: }
324:
325: /*
326: * Check that a proposed value to load into the .it_value or
327: * .it_interval part of an interval timer is acceptable, and
328: * fix it to have at least minimal value (i.e. if it is less
329: * than the resolution of the clock, round it up.)
330: */
1.3 andrew 331: int
1.1 cgd 332: itimerfix(tv)
333: struct timeval *tv;
334: {
335:
336: if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
337: tv->tv_usec < 0 || tv->tv_usec >= 1000000)
338: return (EINVAL);
339: if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
340: tv->tv_usec = tick;
341: return (0);
342: }
343:
344: /*
345: * Decrement an interval timer by a specified number
346: * of microseconds, which must be less than a second,
347: * i.e. < 1000000. If the timer expires, then reload
348: * it. In this case, carry over (usec - old value) to
1.8 cgd 349: * reduce the value reloaded into the timer so that
1.1 cgd 350: * the timer does not drift. This routine assumes
351: * that it is called in a context where the timers
352: * on which it is operating cannot change in value.
353: */
1.3 andrew 354: int
1.1 cgd 355: itimerdecr(itp, usec)
356: register struct itimerval *itp;
357: int usec;
358: {
359:
360: if (itp->it_value.tv_usec < usec) {
361: if (itp->it_value.tv_sec == 0) {
362: /* expired, and already in next interval */
363: usec -= itp->it_value.tv_usec;
364: goto expire;
365: }
366: itp->it_value.tv_usec += 1000000;
367: itp->it_value.tv_sec--;
368: }
369: itp->it_value.tv_usec -= usec;
370: usec = 0;
371: if (timerisset(&itp->it_value))
372: return (1);
373: /* expired, exactly at end of interval */
374: expire:
375: if (timerisset(&itp->it_interval)) {
376: itp->it_value = itp->it_interval;
377: itp->it_value.tv_usec -= usec;
378: if (itp->it_value.tv_usec < 0) {
379: itp->it_value.tv_usec += 1000000;
380: itp->it_value.tv_sec--;
381: }
382: } else
383: itp->it_value.tv_usec = 0; /* sec is already 0 */
384: return (0);
385: }
386:
387: /*
388: * Add and subtract routines for timevals.
389: * N.B.: subtract routine doesn't deal with
390: * results which are before the beginning,
391: * it just gets very confused in this case.
392: * Caveat emptor.
393: */
1.3 andrew 394: void
1.1 cgd 395: timevaladd(t1, t2)
396: struct timeval *t1, *t2;
397: {
398:
399: t1->tv_sec += t2->tv_sec;
400: t1->tv_usec += t2->tv_usec;
401: timevalfix(t1);
402: }
403:
1.3 andrew 404: void
1.1 cgd 405: timevalsub(t1, t2)
406: struct timeval *t1, *t2;
407: {
408:
409: t1->tv_sec -= t2->tv_sec;
410: t1->tv_usec -= t2->tv_usec;
411: timevalfix(t1);
412: }
413:
1.3 andrew 414: void
1.1 cgd 415: timevalfix(t1)
416: struct timeval *t1;
417: {
418:
419: if (t1->tv_usec < 0) {
420: t1->tv_sec--;
421: t1->tv_usec += 1000000;
422: }
423: if (t1->tv_usec >= 1000000) {
424: t1->tv_sec++;
425: t1->tv_usec -= 1000000;
426: }
427: }
CVSweb <webmaster@jp.NetBSD.org>