[BACK]Return to kern_time.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

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>