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