[BACK]Return to kern_time.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_time.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kern_time.c,v 1.62 2007/04/04 17:32:20 art Exp $      */
        !             2: /*     $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $      */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1989, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the University nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  *     @(#)kern_time.c 8.4 (Berkeley) 5/26/95
        !            33:  */
        !            34:
        !            35: #include <sys/param.h>
        !            36: #include <sys/resourcevar.h>
        !            37: #include <sys/kernel.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/proc.h>
        !            40: #include <sys/vnode.h>
        !            41: #include <sys/signalvar.h>
        !            42: #ifdef __HAVE_TIMECOUNTER
        !            43: #include <sys/timetc.h>
        !            44: #endif
        !            45:
        !            46: #include <sys/mount.h>
        !            47: #include <sys/syscallargs.h>
        !            48:
        !            49: #include <machine/cpu.h>
        !            50:
        !            51: void   itimerround(struct timeval *);
        !            52:
        !            53: /*
        !            54:  * Time of day and interval timer support.
        !            55:  *
        !            56:  * These routines provide the kernel entry points to get and set
        !            57:  * the time-of-day and per-process interval timers.  Subroutines
        !            58:  * here provide support for adding and subtracting timeval structures
        !            59:  * and decrementing interval timers, optionally reloading the interval
        !            60:  * timers when they expire.
        !            61:  */
        !            62:
        !            63: /* This function is used by clock_settime and settimeofday */
        !            64: #ifdef __HAVE_TIMECOUNTER
        !            65: int
        !            66: settime(struct timespec *ts)
        !            67: {
        !            68:        struct timespec now;
        !            69:
        !            70:
        !            71:        /*
        !            72:         * Don't allow the time to be set forward so far it will wrap
        !            73:         * and become negative, thus allowing an attacker to bypass
        !            74:         * the next check below.  The cutoff is 1 year before rollover
        !            75:         * occurs, so even if the attacker uses adjtime(2) to move
        !            76:         * the time past the cutoff, it will take a very long time
        !            77:         * to get to the wrap point.
        !            78:         *
        !            79:         * XXX: we check against INT_MAX since on 64-bit
        !            80:         *      platforms, sizeof(int) != sizeof(long) and
        !            81:         *      time_t is 32 bits even when atv.tv_sec is 64 bits.
        !            82:         */
        !            83:        if (ts->tv_sec > INT_MAX - 365*24*60*60) {
        !            84:                printf("denied attempt to set clock forward to %ld\n",
        !            85:                    ts->tv_sec);
        !            86:                return (EPERM);
        !            87:        }
        !            88:        /*
        !            89:         * If the system is secure, we do not allow the time to be
        !            90:         * set to an earlier value (it may be slowed using adjtime,
        !            91:         * but not set back). This feature prevent interlopers from
        !            92:         * setting arbitrary time stamps on files.
        !            93:         */
        !            94:        nanotime(&now);
        !            95:        if (securelevel > 1 && timespeccmp(ts, &now, <)) {
        !            96:                printf("denied attempt to set clock back %ld seconds\n",
        !            97:                    now.tv_sec - ts->tv_sec);
        !            98:                return (EPERM);
        !            99:        }
        !           100:
        !           101:        tc_setclock(ts);
        !           102:        resettodr();
        !           103:
        !           104:        return (0);
        !           105: }
        !           106: #else
        !           107: int
        !           108: settime(struct timespec *ts)
        !           109: {
        !           110:        struct timeval delta, tvv, *tv;
        !           111:        int s;
        !           112:
        !           113:        /* XXX - Ugh. */
        !           114:        tv = &tvv;
        !           115:        tvv.tv_sec = ts->tv_sec;
        !           116:        tvv.tv_usec = ts->tv_nsec / 1000;
        !           117:
        !           118:        /*
        !           119:         * Don't allow the time to be set forward so far it will wrap
        !           120:         * and become negative, thus allowing an attacker to bypass
        !           121:         * the next check below.  The cutoff is 1 year before rollover
        !           122:         * occurs, so even if the attacker uses adjtime(2) to move
        !           123:         * the time past the cutoff, it will take a very long time
        !           124:         * to get to the wrap point.
        !           125:         *
        !           126:         * XXX: we check against INT_MAX since on 64-bit
        !           127:         *      platforms, sizeof(int) != sizeof(long) and
        !           128:         *      time_t is 32 bits even when atv.tv_sec is 64 bits.
        !           129:         */
        !           130:        if (tv->tv_sec > INT_MAX - 365*24*60*60) {
        !           131:                printf("denied attempt to set clock forward to %ld\n",
        !           132:                    tv->tv_sec);
        !           133:                return (EPERM);
        !           134:        }
        !           135:        /*
        !           136:         * If the system is secure, we do not allow the time to be
        !           137:         * set to an earlier value (it may be slowed using adjtime,
        !           138:         * but not set back). This feature prevent interlopers from
        !           139:         * setting arbitrary time stamps on files.
        !           140:         */
        !           141:        if (securelevel > 1 && timercmp(tv, &time, <)) {
        !           142:                printf("denied attempt to set clock back %ld seconds\n",
        !           143:                    time_second - tv->tv_sec);
        !           144:                return (EPERM);
        !           145:        }
        !           146:
        !           147:        /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
        !           148:        s = splclock();
        !           149:        timersub(tv, &time, &delta);
        !           150:        time = *tv;
        !           151:        timeradd(&boottime, &delta, &boottime);
        !           152:        splx(s);
        !           153:        resettodr();
        !           154:
        !           155:        return (0);
        !           156: }
        !           157: #endif
        !           158:
        !           159: /* ARGSUSED */
        !           160: int
        !           161: sys_clock_gettime(struct proc *p, void *v, register_t *retval)
        !           162: {
        !           163:        struct sys_clock_gettime_args /* {
        !           164:                syscallarg(clockid_t) clock_id;
        !           165:                syscallarg(struct timespec *) tp;
        !           166:        } */ *uap = v;
        !           167:        clockid_t clock_id;
        !           168:        struct timespec ats;
        !           169:
        !           170:        clock_id = SCARG(uap, clock_id);
        !           171:        switch (clock_id) {
        !           172:        case CLOCK_REALTIME:
        !           173:                nanotime(&ats);
        !           174:                break;
        !           175:        case CLOCK_MONOTONIC:
        !           176:                nanouptime(&ats);
        !           177:                break;
        !           178:        case CLOCK_PROF:
        !           179:                ats.tv_sec = p->p_rtime.tv_sec;
        !           180:                ats.tv_nsec = p->p_rtime.tv_usec * 1000;
        !           181:                break;
        !           182:        default:
        !           183:                return (EINVAL);
        !           184:        }
        !           185:
        !           186:        return copyout(&ats, SCARG(uap, tp), sizeof(ats));
        !           187: }
        !           188:
        !           189: /* ARGSUSED */
        !           190: int
        !           191: sys_clock_settime(struct proc *p, void *v, register_t *retval)
        !           192: {
        !           193:        struct sys_clock_settime_args /* {
        !           194:                syscallarg(clockid_t) clock_id;
        !           195:                syscallarg(const struct timespec *) tp;
        !           196:        } */ *uap = v;
        !           197:        struct timespec ats;
        !           198:        clockid_t clock_id;
        !           199:        int error;
        !           200:
        !           201:        if ((error = suser(p, 0)) != 0)
        !           202:                return (error);
        !           203:
        !           204:        if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
        !           205:                return (error);
        !           206:
        !           207:        clock_id = SCARG(uap, clock_id);
        !           208:        switch (clock_id) {
        !           209:        case CLOCK_REALTIME:
        !           210:                if ((error = settime(&ats)) != 0)
        !           211:                        return (error);
        !           212:                break;
        !           213:        default:        /* Other clocks are read-only */
        !           214:                return (EINVAL);
        !           215:        }
        !           216:
        !           217:        return (0);
        !           218: }
        !           219:
        !           220: int
        !           221: sys_clock_getres(struct proc *p, void *v, register_t *retval)
        !           222: {
        !           223:        struct sys_clock_getres_args /* {
        !           224:                syscallarg(clockid_t) clock_id;
        !           225:                syscallarg(struct timespec *) tp;
        !           226:        } */ *uap = v;
        !           227:        clockid_t clock_id;
        !           228:        struct timespec ts;
        !           229:        int error = 0;
        !           230:
        !           231:        clock_id = SCARG(uap, clock_id);
        !           232:        switch (clock_id) {
        !           233:        case CLOCK_REALTIME:
        !           234:        case CLOCK_MONOTONIC:
        !           235:                ts.tv_sec = 0;
        !           236:                ts.tv_nsec = 1000000000 / hz;
        !           237:                break;
        !           238:        default:
        !           239:                return (EINVAL);
        !           240:        }
        !           241:
        !           242:        if (SCARG(uap, tp))
        !           243:                error = copyout(&ts, SCARG(uap, tp), sizeof (ts));
        !           244:
        !           245:        return error;
        !           246: }
        !           247:
        !           248: /* ARGSUSED */
        !           249: int
        !           250: sys_nanosleep(struct proc *p, void *v, register_t *retval)
        !           251: {
        !           252:        static int nanowait;
        !           253:        struct sys_nanosleep_args/* {
        !           254:                syscallarg(const struct timespec *) rqtp;
        !           255:                syscallarg(struct timespec *) rmtp;
        !           256:        } */ *uap = v;
        !           257:        struct timespec rqt, rmt;
        !           258:        struct timespec sts, ets;
        !           259:        struct timeval tv;
        !           260:        int error;
        !           261:
        !           262:        error = copyin((const void *)SCARG(uap, rqtp), (void *)&rqt,
        !           263:            sizeof(struct timespec));
        !           264:        if (error)
        !           265:                return (error);
        !           266:
        !           267:        TIMESPEC_TO_TIMEVAL(&tv, &rqt);
        !           268:        if (itimerfix(&tv))
        !           269:                return (EINVAL);
        !           270:
        !           271:        if (SCARG(uap, rmtp))
        !           272:                getnanouptime(&sts);
        !           273:
        !           274:        error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep",
        !           275:            MAX(1, tvtohz(&tv)));
        !           276:        if (error == ERESTART)
        !           277:                error = EINTR;
        !           278:        if (error == EWOULDBLOCK)
        !           279:                error = 0;
        !           280:
        !           281:        if (SCARG(uap, rmtp)) {
        !           282:                getnanouptime(&ets);
        !           283:
        !           284:                timespecsub(&ets, &sts, &sts);
        !           285:                timespecsub(&rqt, &sts, &rmt);
        !           286:
        !           287:                if (rmt.tv_sec < 0)
        !           288:                        timespecclear(&rmt);
        !           289:
        !           290:                error = copyout((void *)&rmt, (void *)SCARG(uap,rmtp),
        !           291:                    sizeof(rmt));
        !           292:        }
        !           293:
        !           294:        return error;
        !           295: }
        !           296:
        !           297: /* ARGSUSED */
        !           298: int
        !           299: sys_gettimeofday(struct proc *p, void *v, register_t *retval)
        !           300: {
        !           301:        struct sys_gettimeofday_args /* {
        !           302:                syscallarg(struct timeval *) tp;
        !           303:                syscallarg(struct timezone *) tzp;
        !           304:        } */ *uap = v;
        !           305:        struct timeval atv;
        !           306:        int error = 0;
        !           307:
        !           308:        if (SCARG(uap, tp)) {
        !           309:                microtime(&atv);
        !           310:                if ((error = copyout((void *)&atv, (void *)SCARG(uap, tp),
        !           311:                    sizeof (atv))))
        !           312:                        return (error);
        !           313:        }
        !           314:        if (SCARG(uap, tzp))
        !           315:                error = copyout((void *)&tz, (void *)SCARG(uap, tzp),
        !           316:                    sizeof (tz));
        !           317:        return (error);
        !           318: }
        !           319:
        !           320: /* ARGSUSED */
        !           321: int
        !           322: sys_settimeofday(struct proc *p, void *v, register_t *retval)
        !           323: {
        !           324:        struct sys_settimeofday_args /* {
        !           325:                syscallarg(const struct timeval *) tv;
        !           326:                syscallarg(const struct timezone *) tzp;
        !           327:        } */ *uap = v;
        !           328:        struct timezone atz;
        !           329:        struct timeval atv;
        !           330:        int error;
        !           331:
        !           332:        if ((error = suser(p, 0)))
        !           333:                return (error);
        !           334:        /* Verify all parameters before changing time. */
        !           335:        if (SCARG(uap, tv) && (error = copyin((void *)SCARG(uap, tv),
        !           336:            (void *)&atv, sizeof(atv))))
        !           337:                return (error);
        !           338:        if (SCARG(uap, tzp) && (error = copyin((void *)SCARG(uap, tzp),
        !           339:            (void *)&atz, sizeof(atz))))
        !           340:                return (error);
        !           341:        if (SCARG(uap, tv)) {
        !           342:                struct timespec ts;
        !           343:
        !           344:                TIMEVAL_TO_TIMESPEC(&atv, &ts);
        !           345:                if ((error = settime(&ts)) != 0)
        !           346:                        return (error);
        !           347:        }
        !           348:        if (SCARG(uap, tzp))
        !           349:                tz = atz;
        !           350:        return (0);
        !           351: }
        !           352:
        !           353: #ifdef __HAVE_TIMECOUNTER
        !           354: struct timeval adjtimedelta;           /* unapplied time correction */
        !           355: #else
        !           356: int    tickdelta;                      /* current clock skew, us. per tick */
        !           357: long   timedelta;                      /* unapplied time correction, us. */
        !           358: long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
        !           359: int64_t        ntp_tick_permanent;
        !           360: int64_t        ntp_tick_acc;
        !           361: #endif
        !           362:
        !           363: /* ARGSUSED */
        !           364: int
        !           365: sys_adjfreq(struct proc *p, void *v, register_t *retval)
        !           366: {
        !           367:        struct sys_adjfreq_args /* {
        !           368:                syscallarg(const int64_t *) freq;
        !           369:                syscallarg(int64_t *) oldfreq;
        !           370:        } */ *uap = v;
        !           371:        int error;
        !           372:        int64_t f;
        !           373: #ifndef __HAVE_TIMECOUNTER
        !           374:        int s;
        !           375:
        !           376:        if (SCARG(uap, oldfreq)) {
        !           377:                f = ntp_tick_permanent * hz;
        !           378:                if ((error = copyout((void *)&f, (void *)SCARG(uap, oldfreq),
        !           379:                    sizeof(int64_t))))
        !           380:                        return (error);
        !           381:        }
        !           382:        if (SCARG(uap, freq)) {
        !           383:                if ((error = suser(p, 0)))
        !           384:                        return (error);
        !           385:                if ((error = copyin((void *)SCARG(uap, freq), (void *)&f,
        !           386:                    sizeof(int64_t))))
        !           387:                        return (error);
        !           388:                s = splclock();
        !           389:                ntp_tick_permanent = f / hz;
        !           390:                splx(s);
        !           391:        }
        !           392: #else
        !           393:        if (SCARG(uap, oldfreq)) {
        !           394:                if ((error = tc_adjfreq(&f, NULL)) != 0)
        !           395:                        return (error);
        !           396:                if ((error = copyout(&f, SCARG(uap, oldfreq), sizeof(f))) != 0)
        !           397:                        return (error);
        !           398:        }
        !           399:        if (SCARG(uap, freq)) {
        !           400:                if ((error = suser(p, 0)))
        !           401:                        return (error);
        !           402:                if ((error = copyin(SCARG(uap, freq), &f, sizeof(f))) != 0)
        !           403:                        return (error);
        !           404:                if ((error = tc_adjfreq(NULL, &f)) != 0)
        !           405:                        return (error);
        !           406:        }
        !           407: #endif
        !           408:        return (0);
        !           409: }
        !           410:
        !           411: /* ARGSUSED */
        !           412: int
        !           413: sys_adjtime(struct proc *p, void *v, register_t *retval)
        !           414: {
        !           415:        struct sys_adjtime_args /* {
        !           416:                syscallarg(const struct timeval *) delta;
        !           417:                syscallarg(struct timeval *) olddelta;
        !           418:        } */ *uap = v;
        !           419: #ifdef __HAVE_TIMECOUNTER
        !           420:        int error;
        !           421:
        !           422:        if (SCARG(uap, olddelta))
        !           423:                if ((error = copyout((void *)&adjtimedelta,
        !           424:                    (void *)SCARG(uap, olddelta), sizeof(struct timeval))))
        !           425:                        return (error);
        !           426:
        !           427:        if (SCARG(uap, delta)) {
        !           428:                if ((error = suser(p, 0)))
        !           429:                        return (error);
        !           430:
        !           431:                if ((error = copyin((void *)SCARG(uap, delta),
        !           432:                    (void *)&adjtimedelta, sizeof(struct timeval))))
        !           433:                        return (error);
        !           434:        }
        !           435:
        !           436:        /* Normalize the correction. */
        !           437:        while (adjtimedelta.tv_usec >= 1000000) {
        !           438:                adjtimedelta.tv_usec -= 1000000;
        !           439:                adjtimedelta.tv_sec += 1;
        !           440:        }
        !           441:        while (adjtimedelta.tv_usec < 0) {
        !           442:                adjtimedelta.tv_usec += 1000000;
        !           443:                adjtimedelta.tv_sec -= 1;
        !           444:        }
        !           445:        return (0);
        !           446: #else
        !           447:        struct timeval atv;
        !           448:        long ndelta, ntickdelta, odelta;
        !           449:        int s, error;
        !           450:
        !           451:        if (!SCARG(uap, delta)) {
        !           452:                s = splclock();
        !           453:                odelta = timedelta;
        !           454:                splx(s);
        !           455:                goto out;
        !           456:        }
        !           457:        if ((error = suser(p, 0)))
        !           458:                return (error);
        !           459:        if ((error = copyin((void *)SCARG(uap, delta), (void *)&atv,
        !           460:            sizeof(struct timeval))))
        !           461:                return (error);
        !           462:
        !           463:        /*
        !           464:         * Compute the total correction and the rate at which to apply it.
        !           465:         * Round the adjustment down to a whole multiple of the per-tick
        !           466:         * delta, so that after some number of incremental changes in
        !           467:         * hardclock(), tickdelta will become zero, lest the correction
        !           468:         * overshoot and start taking us away from the desired final time.
        !           469:         */
        !           470:        if (atv.tv_sec > LONG_MAX / 1000000L)
        !           471:                ndelta = LONG_MAX;
        !           472:        else if (atv.tv_sec < LONG_MIN / 1000000L)
        !           473:                ndelta = LONG_MIN;
        !           474:        else {
        !           475:                ndelta = atv.tv_sec * 1000000L;
        !           476:                odelta = ndelta;
        !           477:                ndelta += atv.tv_usec;
        !           478:                if (atv.tv_usec > 0 && ndelta <= odelta)
        !           479:                        ndelta = LONG_MAX;
        !           480:                else if (atv.tv_usec < 0 && ndelta >= odelta)
        !           481:                        ndelta = LONG_MIN;
        !           482:        }
        !           483:
        !           484:        if (ndelta > bigadj || ndelta < -bigadj)
        !           485:                ntickdelta = 10 * tickadj;
        !           486:        else
        !           487:                ntickdelta = tickadj;
        !           488:        if (ndelta % ntickdelta)
        !           489:                ndelta = ndelta / ntickdelta * ntickdelta;
        !           490:
        !           491:        /*
        !           492:         * To make hardclock()'s job easier, make the per-tick delta negative
        !           493:         * if we want time to run slower; then hardclock can simply compute
        !           494:         * tick + tickdelta, and subtract tickdelta from timedelta.
        !           495:         */
        !           496:        if (ndelta < 0)
        !           497:                ntickdelta = -ntickdelta;
        !           498:        s = splclock();
        !           499:        odelta = timedelta;
        !           500:        timedelta = ndelta;
        !           501:        tickdelta = ntickdelta;
        !           502:        splx(s);
        !           503:
        !           504: out:
        !           505:        if (SCARG(uap, olddelta)) {
        !           506:                atv.tv_sec = odelta / 1000000;
        !           507:                atv.tv_usec = odelta % 1000000;
        !           508:                if ((error = copyout((void *)&atv, (void *)SCARG(uap, olddelta),
        !           509:                    sizeof(struct timeval))))
        !           510:                        return (error);
        !           511:        }
        !           512:        return (0);
        !           513: #endif
        !           514: }
        !           515:
        !           516:
        !           517: /*
        !           518:  * Get value of an interval timer.  The process virtual and
        !           519:  * profiling virtual time timers are kept in the p_stats area, since
        !           520:  * they can be swapped out.  These are kept internally in the
        !           521:  * way they are specified externally: in time until they expire.
        !           522:  *
        !           523:  * The real time interval timer is kept in the process table slot
        !           524:  * for the process, and its value (it_value) is kept as an
        !           525:  * absolute time rather than as a delta, so that it is easy to keep
        !           526:  * periodic real-time signals from drifting.
        !           527:  *
        !           528:  * Virtual time timers are processed in the hardclock() routine of
        !           529:  * kern_clock.c.  The real time timer is processed by a timeout
        !           530:  * routine, called from the softclock() routine.  Since a callout
        !           531:  * may be delayed in real time due to interrupt processing in the system,
        !           532:  * it is possible for the real time timeout routine (realitexpire, given below),
        !           533:  * to be delayed in real time past when it is supposed to occur.  It
        !           534:  * does not suffice, therefore, to reload the real timer .it_value from the
        !           535:  * real time timers .it_interval.  Rather, we compute the next time in
        !           536:  * absolute time the timer should go off.
        !           537:  */
        !           538: /* ARGSUSED */
        !           539: int
        !           540: sys_getitimer(struct proc *p, void *v, register_t *retval)
        !           541: {
        !           542:        struct sys_getitimer_args /* {
        !           543:                syscallarg(int) which;
        !           544:                syscallarg(struct itimerval *) itv;
        !           545:        } */ *uap = v;
        !           546:        struct itimerval aitv;
        !           547:        int s;
        !           548:
        !           549:        if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
        !           550:                return (EINVAL);
        !           551:        s = splclock();
        !           552:        if (SCARG(uap, which) == ITIMER_REAL) {
        !           553:                struct timeval now;
        !           554:
        !           555:                getmicrouptime(&now);
        !           556:                /*
        !           557:                 * Convert from absolute to relative time in .it_value
        !           558:                 * part of real time timer.  If time for real time timer
        !           559:                 * has passed return 0, else return difference between
        !           560:                 * current time and time for the timer to go off.
        !           561:                 */
        !           562:                aitv = p->p_realtimer;
        !           563:                if (timerisset(&aitv.it_value)) {
        !           564:                        if (timercmp(&aitv.it_value, &now, <))
        !           565:                                timerclear(&aitv.it_value);
        !           566:                        else
        !           567:                                timersub(&aitv.it_value, &now,
        !           568:                                    &aitv.it_value);
        !           569:                }
        !           570:        } else
        !           571:                aitv = p->p_stats->p_timer[SCARG(uap, which)];
        !           572:        splx(s);
        !           573:        return (copyout((void *)&aitv, (void *)SCARG(uap, itv),
        !           574:            sizeof (struct itimerval)));
        !           575: }
        !           576:
        !           577: /* ARGSUSED */
        !           578: int
        !           579: sys_setitimer(struct proc *p, void *v, register_t *retval)
        !           580: {
        !           581:        struct sys_setitimer_args /* {
        !           582:                syscallarg(int) which;
        !           583:                syscallarg(const struct itimerval *) itv;
        !           584:                syscallarg(struct itimerval *) oitv;
        !           585:        } */ *uap = v;
        !           586:        struct sys_getitimer_args getargs;
        !           587:        struct itimerval aitv;
        !           588:        const struct itimerval *itvp;
        !           589:        int error;
        !           590:        int timo;
        !           591:
        !           592:        if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
        !           593:                return (EINVAL);
        !           594:        itvp = SCARG(uap, itv);
        !           595:        if (itvp && (error = copyin((void *)itvp, (void *)&aitv,
        !           596:            sizeof(struct itimerval))))
        !           597:                return (error);
        !           598:        if (SCARG(uap, oitv) != NULL) {
        !           599:                SCARG(&getargs, which) = SCARG(uap, which);
        !           600:                SCARG(&getargs, itv) = SCARG(uap, oitv);
        !           601:                if ((error = sys_getitimer(p, &getargs, retval)))
        !           602:                        return (error);
        !           603:        }
        !           604:        if (itvp == 0)
        !           605:                return (0);
        !           606:        if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
        !           607:                return (EINVAL);
        !           608:        if (SCARG(uap, which) == ITIMER_REAL) {
        !           609:                struct timeval ctv;
        !           610:
        !           611:                timeout_del(&p->p_realit_to);
        !           612:                getmicrouptime(&ctv);
        !           613:                if (timerisset(&aitv.it_value)) {
        !           614:                        timo = tvtohz(&aitv.it_value);
        !           615:                        timeout_add(&p->p_realit_to, timo);
        !           616:                        timeradd(&aitv.it_value, &ctv, &aitv.it_value);
        !           617:                }
        !           618:                p->p_realtimer = aitv;
        !           619:        } else {
        !           620:                int s;
        !           621:
        !           622:                itimerround(&aitv.it_interval);
        !           623:                s = splclock();
        !           624:                p->p_stats->p_timer[SCARG(uap, which)] = aitv;
        !           625:                splx(s);
        !           626:        }
        !           627:
        !           628:        return (0);
        !           629: }
        !           630:
        !           631: /*
        !           632:  * Real interval timer expired:
        !           633:  * send process whose timer expired an alarm signal.
        !           634:  * If time is not set up to reload, then just return.
        !           635:  * Else compute next time timer should go off which is > current time.
        !           636:  * This is where delay in processing this timeout causes multiple
        !           637:  * SIGALRM calls to be compressed into one.
        !           638:  */
        !           639: void
        !           640: realitexpire(void *arg)
        !           641: {
        !           642:        struct proc *p;
        !           643:
        !           644:        p = (struct proc *)arg;
        !           645:        psignal(p, SIGALRM);
        !           646:        if (!timerisset(&p->p_realtimer.it_interval)) {
        !           647:                timerclear(&p->p_realtimer.it_value);
        !           648:                return;
        !           649:        }
        !           650:        for (;;) {
        !           651:                struct timeval ctv, ntv;
        !           652:                int timo;
        !           653:
        !           654:                timeradd(&p->p_realtimer.it_value,
        !           655:                    &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
        !           656:                getmicrouptime(&ctv);
        !           657:                if (timercmp(&p->p_realtimer.it_value, &ctv, >)) {
        !           658:                        ntv = p->p_realtimer.it_value;
        !           659:                        timersub(&ntv, &ctv, &ntv);
        !           660:                        timo = tvtohz(&ntv) - 1;
        !           661:                        if (timo <= 0)
        !           662:                                timo = 1;
        !           663:                        if ((p->p_flag & P_WEXIT) == 0)
        !           664:                                timeout_add(&p->p_realit_to, timo);
        !           665:                        return;
        !           666:                }
        !           667:        }
        !           668: }
        !           669:
        !           670: /*
        !           671:  * Check that a proposed value to load into the .it_value or
        !           672:  * .it_interval part of an interval timer is acceptable.
        !           673:  */
        !           674: int
        !           675: itimerfix(struct timeval *tv)
        !           676: {
        !           677:
        !           678:        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
        !           679:            tv->tv_usec < 0 || tv->tv_usec >= 1000000)
        !           680:                return (EINVAL);
        !           681:
        !           682:        if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
        !           683:                tv->tv_usec = tick;
        !           684:
        !           685:        return (0);
        !           686: }
        !           687:
        !           688: /*
        !           689:  * Timer interval smaller than the resolution of the system clock are
        !           690:  * rounded up.
        !           691:  */
        !           692: void
        !           693: itimerround(struct timeval *tv)
        !           694: {
        !           695:        if (tv->tv_sec == 0 && tv->tv_usec < tick)
        !           696:                tv->tv_usec = tick;
        !           697: }
        !           698:
        !           699: /*
        !           700:  * Decrement an interval timer by a specified number
        !           701:  * of microseconds, which must be less than a second,
        !           702:  * i.e. < 1000000.  If the timer expires, then reload
        !           703:  * it.  In this case, carry over (usec - old value) to
        !           704:  * reduce the value reloaded into the timer so that
        !           705:  * the timer does not drift.  This routine assumes
        !           706:  * that it is called in a context where the timers
        !           707:  * on which it is operating cannot change in value.
        !           708:  */
        !           709: int
        !           710: itimerdecr(struct itimerval *itp, int usec)
        !           711: {
        !           712:
        !           713:        if (itp->it_value.tv_usec < usec) {
        !           714:                if (itp->it_value.tv_sec == 0) {
        !           715:                        /* expired, and already in next interval */
        !           716:                        usec -= itp->it_value.tv_usec;
        !           717:                        goto expire;
        !           718:                }
        !           719:                itp->it_value.tv_usec += 1000000;
        !           720:                itp->it_value.tv_sec--;
        !           721:        }
        !           722:        itp->it_value.tv_usec -= usec;
        !           723:        usec = 0;
        !           724:        if (timerisset(&itp->it_value))
        !           725:                return (1);
        !           726:        /* expired, exactly at end of interval */
        !           727: expire:
        !           728:        if (timerisset(&itp->it_interval)) {
        !           729:                itp->it_value = itp->it_interval;
        !           730:                itp->it_value.tv_usec -= usec;
        !           731:                if (itp->it_value.tv_usec < 0) {
        !           732:                        itp->it_value.tv_usec += 1000000;
        !           733:                        itp->it_value.tv_sec--;
        !           734:                }
        !           735:        } else
        !           736:                itp->it_value.tv_usec = 0;              /* sec is already 0 */
        !           737:        return (0);
        !           738: }
        !           739:
        !           740: /*
        !           741:  * ratecheck(): simple time-based rate-limit checking.  see ratecheck(9)
        !           742:  * for usage and rationale.
        !           743:  */
        !           744: int
        !           745: ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
        !           746: {
        !           747:        struct timeval tv, delta;
        !           748:        int rv = 0;
        !           749:
        !           750:        microuptime(&tv);
        !           751:
        !           752:        timersub(&tv, lasttime, &delta);
        !           753:
        !           754:        /*
        !           755:         * check for 0,0 is so that the message will be seen at least once,
        !           756:         * even if interval is huge.
        !           757:         */
        !           758:        if (timercmp(&delta, mininterval, >=) ||
        !           759:            (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
        !           760:                *lasttime = tv;
        !           761:                rv = 1;
        !           762:        }
        !           763:
        !           764:        return (rv);
        !           765: }
        !           766:
        !           767: /*
        !           768:  * ppsratecheck(): packets (or events) per second limitation.
        !           769:  */
        !           770: int
        !           771: ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
        !           772: {
        !           773:        struct timeval tv, delta;
        !           774:        int rv;
        !           775:
        !           776:        microuptime(&tv);
        !           777:
        !           778:        timersub(&tv, lasttime, &delta);
        !           779:
        !           780:        /*
        !           781:         * check for 0,0 is so that the message will be seen at least once.
        !           782:         * if more than one second have passed since the last update of
        !           783:         * lasttime, reset the counter.
        !           784:         *
        !           785:         * we do increment *curpps even in *curpps < maxpps case, as some may
        !           786:         * try to use *curpps for stat purposes as well.
        !           787:         */
        !           788:        if (maxpps == 0)
        !           789:                rv = 0;
        !           790:        else if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
        !           791:            delta.tv_sec >= 1) {
        !           792:                *lasttime = tv;
        !           793:                *curpps = 0;
        !           794:                rv = 1;
        !           795:        } else if (maxpps < 0)
        !           796:                rv = 1;
        !           797:        else if (*curpps < maxpps)
        !           798:                rv = 1;
        !           799:        else
        !           800:                rv = 0;
        !           801:
        !           802: #if 1 /*DIAGNOSTIC?*/
        !           803:        /* be careful about wrap-around */
        !           804:        if (*curpps + 1 > *curpps)
        !           805:                *curpps = *curpps + 1;
        !           806: #else
        !           807:        /*
        !           808:         * assume that there's not too many calls to this function.
        !           809:         * not sure if the assumption holds, as it depends on *caller's*
        !           810:         * behavior, not the behavior of this function.
        !           811:         * IMHO it is wrong to make assumption on the caller's behavior,
        !           812:         * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
        !           813:         */
        !           814:        *curpps = *curpps + 1;
        !           815: #endif
        !           816:
        !           817:        return (rv);
        !           818: }

CVSweb