[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.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>