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

1.50    ! itojun      1: /*     $NetBSD: kern_time.c,v 1.49 2000/07/09 06:40:08 itojun Exp $    */
1.42      cgd         2:
                      3: /*-
                      4:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Christopher G. Demetriou.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the NetBSD
                     21:  *     Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
1.9       cgd        38:
1.1       cgd        39: /*
1.8       cgd        40:  * Copyright (c) 1982, 1986, 1989, 1993
                     41:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *     This product includes software developed by the University of
                     54:  *     California, Berkeley and its contributors.
                     55:  * 4. Neither the name of the University nor the names of its contributors
                     56:  *    may be used to endorse or promote products derived from this software
                     57:  *    without specific prior written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     61:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     62:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     63:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     64:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     65:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     66:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     67:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     69:  * SUCH DAMAGE.
                     70:  *
1.33      fvdl       71:  *     @(#)kern_time.c 8.4 (Berkeley) 5/26/95
1.1       cgd        72:  */
1.31      thorpej    73:
                     74: #include "fs_nfs.h"
1.34      thorpej    75: #include "opt_nfsserver.h"
1.1       cgd        76:
1.5       mycroft    77: #include <sys/param.h>
                     78: #include <sys/resourcevar.h>
                     79: #include <sys/kernel.h>
1.8       cgd        80: #include <sys/systm.h>
1.5       mycroft    81: #include <sys/proc.h>
1.8       cgd        82: #include <sys/vnode.h>
1.17      christos   83: #include <sys/signalvar.h>
1.25      perry      84: #include <sys/syslog.h>
1.1       cgd        85:
1.11      cgd        86: #include <sys/mount.h>
                     87: #include <sys/syscallargs.h>
1.19      christos   88:
1.37      thorpej    89: #include <uvm/uvm_extern.h>
                     90:
1.26      thorpej    91: #if defined(NFS) || defined(NFSSERVER)
1.20      fvdl       92: #include <nfs/rpcv2.h>
                     93: #include <nfs/nfsproto.h>
1.19      christos   94: #include <nfs/nfs_var.h>
                     95: #endif
1.17      christos   96:
1.5       mycroft    97: #include <machine/cpu.h>
1.23      cgd        98:
                     99: /*
1.1       cgd       100:  * Time of day and interval timer support.
                    101:  *
                    102:  * These routines provide the kernel entry points to get and set
                    103:  * the time-of-day and per-process interval timers.  Subroutines
                    104:  * here provide support for adding and subtracting timeval structures
                    105:  * and decrementing interval timers, optionally reloading the interval
                    106:  * timers when they expire.
                    107:  */
                    108:
1.22      jtc       109: /* This function is used by clock_settime and settimeofday */
1.39      tron      110: int
1.22      jtc       111: settime(tv)
                    112:        struct timeval *tv;
                    113: {
                    114:        struct timeval delta;
1.47      thorpej   115:        struct cpu_info *ci;
1.22      jtc       116:        int s;
                    117:
                    118:        /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
                    119:        s = splclock();
                    120:        timersub(tv, &time, &delta);
1.29      tls       121:        if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1)
                    122:                return (EPERM);
                    123: #ifdef notyet
                    124:        if ((delta.tv_sec < 86400) && securelevel > 0)
                    125:                return (EPERM);
                    126: #endif
1.22      jtc       127:        time = *tv;
1.38      thorpej   128:        (void) spllowersoftclock();
1.22      jtc       129:        timeradd(&boottime, &delta, &boottime);
1.47      thorpej   130:        /*
                    131:         * XXXSMP
                    132:         * This is wrong.  We should traverse a list of all
                    133:         * CPUs and add the delta to the runtime of those
                    134:         * CPUs which have a process on them.
                    135:         */
                    136:        ci = curcpu();
                    137:        timeradd(&ci->ci_schedstate.spc_runtime, &delta,
                    138:            &ci->ci_schedstate.spc_runtime);
1.26      thorpej   139: #      if defined(NFS) || defined(NFSSERVER)
1.22      jtc       140:                nqnfs_lease_updatetime(delta.tv_sec);
                    141: #      endif
                    142:        splx(s);
                    143:        resettodr();
1.29      tls       144:        return (0);
1.22      jtc       145: }
                    146:
                    147: /* ARGSUSED */
                    148: int
                    149: sys_clock_gettime(p, v, retval)
                    150:        struct proc *p;
                    151:        void *v;
                    152:        register_t *retval;
                    153: {
1.45      augustss  154:        struct sys_clock_gettime_args /* {
1.22      jtc       155:                syscallarg(clockid_t) clock_id;
1.23      cgd       156:                syscallarg(struct timespec *) tp;
                    157:        } */ *uap = v;
1.22      jtc       158:        clockid_t clock_id;
                    159:        struct timeval atv;
                    160:        struct timespec ats;
                    161:
                    162:        clock_id = SCARG(uap, clock_id);
                    163:        if (clock_id != CLOCK_REALTIME)
                    164:                return (EINVAL);
                    165:
                    166:        microtime(&atv);
                    167:        TIMEVAL_TO_TIMESPEC(&atv,&ats);
                    168:
1.24      cgd       169:        return copyout(&ats, SCARG(uap, tp), sizeof(ats));
1.22      jtc       170: }
                    171:
                    172: /* ARGSUSED */
                    173: int
                    174: sys_clock_settime(p, v, retval)
                    175:        struct proc *p;
                    176:        void *v;
                    177:        register_t *retval;
                    178: {
1.45      augustss  179:        struct sys_clock_settime_args /* {
1.22      jtc       180:                syscallarg(clockid_t) clock_id;
1.23      cgd       181:                syscallarg(const struct timespec *) tp;
                    182:        } */ *uap = v;
1.22      jtc       183:        clockid_t clock_id;
                    184:        struct timeval atv;
                    185:        struct timespec ats;
                    186:        int error;
                    187:
                    188:        if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
                    189:                return (error);
                    190:
                    191:        clock_id = SCARG(uap, clock_id);
                    192:        if (clock_id != CLOCK_REALTIME)
                    193:                return (EINVAL);
                    194:
1.24      cgd       195:        if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
1.23      cgd       196:                return (error);
1.22      jtc       197:
                    198:        TIMESPEC_TO_TIMEVAL(&atv,&ats);
1.29      tls       199:        if ((error = settime(&atv)))
                    200:                return (error);
1.22      jtc       201:
                    202:        return 0;
                    203: }
                    204:
                    205: int
                    206: sys_clock_getres(p, v, retval)
                    207:        struct proc *p;
                    208:        void *v;
                    209:        register_t *retval;
                    210: {
1.45      augustss  211:        struct sys_clock_getres_args /* {
1.22      jtc       212:                syscallarg(clockid_t) clock_id;
1.23      cgd       213:                syscallarg(struct timespec *) tp;
                    214:        } */ *uap = v;
1.22      jtc       215:        clockid_t clock_id;
                    216:        struct timespec ts;
                    217:        int error = 0;
                    218:
                    219:        clock_id = SCARG(uap, clock_id);
                    220:        if (clock_id != CLOCK_REALTIME)
                    221:                return (EINVAL);
                    222:
                    223:        if (SCARG(uap, tp)) {
                    224:                ts.tv_sec = 0;
                    225:                ts.tv_nsec = 1000000000 / hz;
                    226:
1.35      perry     227:                error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
1.22      jtc       228:        }
                    229:
                    230:        return error;
                    231: }
                    232:
1.27      jtc       233: /* ARGSUSED */
                    234: int
                    235: sys_nanosleep(p, v, retval)
                    236:        struct proc *p;
                    237:        void *v;
                    238:        register_t *retval;
                    239: {
                    240:        static int nanowait;
1.45      augustss  241:        struct sys_nanosleep_args/* {
1.27      jtc       242:                syscallarg(struct timespec *) rqtp;
                    243:                syscallarg(struct timespec *) rmtp;
                    244:        } */ *uap = v;
                    245:        struct timespec rqt;
                    246:        struct timespec rmt;
                    247:        struct timeval atv, utv;
                    248:        int error, s, timo;
                    249:
                    250:        error = copyin((caddr_t)SCARG(uap, rqtp), (caddr_t)&rqt,
                    251:                       sizeof(struct timespec));
                    252:        if (error)
                    253:                return (error);
                    254:
                    255:        TIMESPEC_TO_TIMEVAL(&atv,&rqt)
                    256:        if (itimerfix(&atv))
                    257:                return (EINVAL);
                    258:
                    259:        s = splclock();
                    260:        timeradd(&atv,&time,&atv);
                    261:        timo = hzto(&atv);
                    262:        /*
                    263:         * Avoid inadvertantly sleeping forever
                    264:         */
                    265:        if (timo == 0)
                    266:                timo = 1;
                    267:        splx(s);
                    268:
                    269:        error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
                    270:        if (error == ERESTART)
                    271:                error = EINTR;
                    272:        if (error == EWOULDBLOCK)
                    273:                error = 0;
                    274:
                    275:        if (SCARG(uap, rmtp)) {
1.28      jtc       276:                int error;
                    277:
1.27      jtc       278:                s = splclock();
                    279:                utv = time;
                    280:                splx(s);
                    281:
                    282:                timersub(&atv, &utv, &utv);
                    283:                if (utv.tv_sec < 0)
                    284:                        timerclear(&utv);
                    285:
                    286:                TIMEVAL_TO_TIMESPEC(&utv,&rmt);
                    287:                error = copyout((caddr_t)&rmt, (caddr_t)SCARG(uap,rmtp),
1.28      jtc       288:                        sizeof(rmt));
                    289:                if (error)
                    290:                        return (error);
1.27      jtc       291:        }
                    292:
                    293:        return error;
                    294: }
1.22      jtc       295:
1.1       cgd       296: /* ARGSUSED */
1.3       andrew    297: int
1.16      mycroft   298: sys_gettimeofday(p, v, retval)
1.1       cgd       299:        struct proc *p;
1.15      thorpej   300:        void *v;
                    301:        register_t *retval;
                    302: {
1.45      augustss  303:        struct sys_gettimeofday_args /* {
1.11      cgd       304:                syscallarg(struct timeval *) tp;
                    305:                syscallarg(struct timezone *) tzp;
1.15      thorpej   306:        } */ *uap = v;
1.1       cgd       307:        struct timeval atv;
                    308:        int error = 0;
1.25      perry     309:        struct timezone tzfake;
1.1       cgd       310:
1.11      cgd       311:        if (SCARG(uap, tp)) {
1.1       cgd       312:                microtime(&atv);
1.35      perry     313:                error = copyout(&atv, SCARG(uap, tp), sizeof(atv));
1.17      christos  314:                if (error)
1.1       cgd       315:                        return (error);
                    316:        }
1.25      perry     317:        if (SCARG(uap, tzp)) {
                    318:                /*
1.32      mycroft   319:                 * NetBSD has no kernel notion of time zone, so we just
1.25      perry     320:                 * fake up a timezone struct and return it if demanded.
                    321:                 */
                    322:                tzfake.tz_minuteswest = 0;
                    323:                tzfake.tz_dsttime = 0;
1.35      perry     324:                error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
1.25      perry     325:        }
1.1       cgd       326:        return (error);
                    327: }
                    328:
                    329: /* ARGSUSED */
1.3       andrew    330: int
1.16      mycroft   331: sys_settimeofday(p, v, retval)
1.1       cgd       332:        struct proc *p;
1.15      thorpej   333:        void *v;
                    334:        register_t *retval;
                    335: {
1.16      mycroft   336:        struct sys_settimeofday_args /* {
1.24      cgd       337:                syscallarg(const struct timeval *) tv;
                    338:                syscallarg(const struct timezone *) tzp;
1.15      thorpej   339:        } */ *uap = v;
1.22      jtc       340:        struct timeval atv;
1.1       cgd       341:        struct timezone atz;
1.22      jtc       342:        int error;
1.1       cgd       343:
1.17      christos  344:        if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1.1       cgd       345:                return (error);
1.8       cgd       346:        /* Verify all parameters before changing time. */
1.24      cgd       347:        if (SCARG(uap, tv) && (error = copyin(SCARG(uap, tv),
                    348:            &atv, sizeof(atv))))
1.8       cgd       349:                return (error);
1.25      perry     350:        /* XXX since we don't use tz, probably no point in doing copyin. */
1.24      cgd       351:        if (SCARG(uap, tzp) && (error = copyin(SCARG(uap, tzp),
                    352:            &atz, sizeof(atz))))
1.8       cgd       353:                return (error);
1.22      jtc       354:        if (SCARG(uap, tv))
1.29      tls       355:                if ((error = settime(&atv)))
                    356:                        return (error);
1.25      perry     357:        /*
1.32      mycroft   358:         * NetBSD has no kernel notion of time zone, and only an
1.25      perry     359:         * obsolete program would try to set it, so we log a warning.
                    360:         */
1.11      cgd       361:        if (SCARG(uap, tzp))
1.25      perry     362:                log(LOG_WARNING, "pid %d attempted to set the "
1.32      mycroft   363:                    "(obsolete) kernel time zone\n", p->p_pid);
1.8       cgd       364:        return (0);
1.1       cgd       365: }
                    366:
                    367: int    tickdelta;                      /* current clock skew, us. per tick */
                    368: long   timedelta;                      /* unapplied time correction, us. */
                    369: long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
                    370:
                    371: /* ARGSUSED */
1.3       andrew    372: int
1.16      mycroft   373: sys_adjtime(p, v, retval)
1.1       cgd       374:        struct proc *p;
1.15      thorpej   375:        void *v;
                    376:        register_t *retval;
                    377: {
1.45      augustss  378:        struct sys_adjtime_args /* {
1.24      cgd       379:                syscallarg(const struct timeval *) delta;
1.11      cgd       380:                syscallarg(struct timeval *) olddelta;
1.15      thorpej   381:        } */ *uap = v;
1.8       cgd       382:        struct timeval atv;
1.45      augustss  383:        long ndelta, ntickdelta, odelta;
1.1       cgd       384:        int s, error;
                    385:
1.17      christos  386:        if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1.1       cgd       387:                return (error);
1.17      christos  388:
1.24      cgd       389:        error = copyin(SCARG(uap, delta), &atv, sizeof(struct timeval));
1.17      christos  390:        if (error)
1.1       cgd       391:                return (error);
1.37      thorpej   392:        if (SCARG(uap, olddelta) != NULL &&
                    393:            uvm_useracc((caddr_t)SCARG(uap, olddelta), sizeof(struct timeval),
                    394:             B_WRITE) == FALSE)
                    395:                return (EFAULT);
1.8       cgd       396:
                    397:        /*
                    398:         * Compute the total correction and the rate at which to apply it.
                    399:         * Round the adjustment down to a whole multiple of the per-tick
                    400:         * delta, so that after some number of incremental changes in
                    401:         * hardclock(), tickdelta will become zero, lest the correction
                    402:         * overshoot and start taking us away from the desired final time.
                    403:         */
1.1       cgd       404:        ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
1.41      hwr       405:        if (ndelta > bigadj || ndelta < -bigadj)
1.8       cgd       406:                ntickdelta = 10 * tickadj;
                    407:        else
                    408:                ntickdelta = tickadj;
                    409:        if (ndelta % ntickdelta)
                    410:                ndelta = ndelta / ntickdelta * ntickdelta;
                    411:
                    412:        /*
                    413:         * To make hardclock()'s job easier, make the per-tick delta negative
                    414:         * if we want time to run slower; then hardclock can simply compute
                    415:         * tick + tickdelta, and subtract tickdelta from timedelta.
                    416:         */
                    417:        if (ndelta < 0)
                    418:                ntickdelta = -ntickdelta;
1.1       cgd       419:        s = splclock();
1.8       cgd       420:        odelta = timedelta;
1.1       cgd       421:        timedelta = ndelta;
1.8       cgd       422:        tickdelta = ntickdelta;
1.1       cgd       423:        splx(s);
                    424:
1.11      cgd       425:        if (SCARG(uap, olddelta)) {
1.8       cgd       426:                atv.tv_sec = odelta / 1000000;
                    427:                atv.tv_usec = odelta % 1000000;
1.24      cgd       428:                (void) copyout(&atv, SCARG(uap, olddelta),
1.8       cgd       429:                    sizeof(struct timeval));
                    430:        }
1.1       cgd       431:        return (0);
                    432: }
                    433:
                    434: /*
                    435:  * Get value of an interval timer.  The process virtual and
                    436:  * profiling virtual time timers are kept in the p_stats area, since
                    437:  * they can be swapped out.  These are kept internally in the
                    438:  * way they are specified externally: in time until they expire.
                    439:  *
                    440:  * The real time interval timer is kept in the process table slot
                    441:  * for the process, and its value (it_value) is kept as an
                    442:  * absolute time rather than as a delta, so that it is easy to keep
                    443:  * periodic real-time signals from drifting.
                    444:  *
                    445:  * Virtual time timers are processed in the hardclock() routine of
                    446:  * kern_clock.c.  The real time timer is processed by a timeout
                    447:  * routine, called from the softclock() routine.  Since a callout
                    448:  * may be delayed in real time due to interrupt processing in the system,
                    449:  * it is possible for the real time timeout routine (realitexpire, given below),
                    450:  * to be delayed in real time past when it is supposed to occur.  It
                    451:  * does not suffice, therefore, to reload the real timer .it_value from the
                    452:  * real time timers .it_interval.  Rather, we compute the next time in
                    453:  * absolute time the timer should go off.
                    454:  */
                    455: /* ARGSUSED */
1.3       andrew    456: int
1.16      mycroft   457: sys_getitimer(p, v, retval)
1.1       cgd       458:        struct proc *p;
1.15      thorpej   459:        void *v;
                    460:        register_t *retval;
                    461: {
1.45      augustss  462:        struct sys_getitimer_args /* {
1.30      mycroft   463:                syscallarg(int) which;
1.11      cgd       464:                syscallarg(struct itimerval *) itv;
1.15      thorpej   465:        } */ *uap = v;
1.30      mycroft   466:        int which = SCARG(uap, which);
1.1       cgd       467:        struct itimerval aitv;
                    468:        int s;
                    469:
1.30      mycroft   470:        if ((u_int)which > ITIMER_PROF)
1.1       cgd       471:                return (EINVAL);
                    472:        s = splclock();
1.30      mycroft   473:        if (which == ITIMER_REAL) {
1.1       cgd       474:                /*
1.12      mycroft   475:                 * Convert from absolute to relative time in .it_value
1.1       cgd       476:                 * part of real time timer.  If time for real time timer
                    477:                 * has passed return 0, else return difference between
                    478:                 * current time and time for the timer to go off.
                    479:                 */
                    480:                aitv = p->p_realtimer;
1.36      thorpej   481:                if (timerisset(&aitv.it_value)) {
1.1       cgd       482:                        if (timercmp(&aitv.it_value, &time, <))
                    483:                                timerclear(&aitv.it_value);
                    484:                        else
1.14      mycroft   485:                                timersub(&aitv.it_value, &time, &aitv.it_value);
1.36      thorpej   486:                }
1.1       cgd       487:        } else
1.30      mycroft   488:                aitv = p->p_stats->p_timer[which];
1.1       cgd       489:        splx(s);
1.35      perry     490:        return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
1.1       cgd       491: }
                    492:
                    493: /* ARGSUSED */
1.3       andrew    494: int
1.16      mycroft   495: sys_setitimer(p, v, retval)
1.1       cgd       496:        struct proc *p;
1.45      augustss  497:        void *v;
1.15      thorpej   498:        register_t *retval;
                    499: {
1.45      augustss  500:        struct sys_setitimer_args /* {
1.30      mycroft   501:                syscallarg(int) which;
1.24      cgd       502:                syscallarg(const struct itimerval *) itv;
1.11      cgd       503:                syscallarg(struct itimerval *) oitv;
1.15      thorpej   504:        } */ *uap = v;
1.30      mycroft   505:        int which = SCARG(uap, which);
1.21      cgd       506:        struct sys_getitimer_args getargs;
1.1       cgd       507:        struct itimerval aitv;
1.45      augustss  508:        const struct itimerval *itvp;
1.1       cgd       509:        int s, error;
                    510:
1.30      mycroft   511:        if ((u_int)which > ITIMER_PROF)
1.1       cgd       512:                return (EINVAL);
1.11      cgd       513:        itvp = SCARG(uap, itv);
1.24      cgd       514:        if (itvp && (error = copyin(itvp, &aitv, sizeof(struct itimerval))))
1.1       cgd       515:                return (error);
1.21      cgd       516:        if (SCARG(uap, oitv) != NULL) {
1.30      mycroft   517:                SCARG(&getargs, which) = which;
1.21      cgd       518:                SCARG(&getargs, itv) = SCARG(uap, oitv);
1.23      cgd       519:                if ((error = sys_getitimer(p, &getargs, retval)) != 0)
1.21      cgd       520:                        return (error);
                    521:        }
1.1       cgd       522:        if (itvp == 0)
                    523:                return (0);
                    524:        if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
                    525:                return (EINVAL);
                    526:        s = splclock();
1.30      mycroft   527:        if (which == ITIMER_REAL) {
1.44      thorpej   528:                callout_stop(&p->p_realit_ch);
1.1       cgd       529:                if (timerisset(&aitv.it_value)) {
1.14      mycroft   530:                        timeradd(&aitv.it_value, &time, &aitv.it_value);
1.44      thorpej   531:                        callout_reset(&p->p_realit_ch, hzto(&aitv.it_value),
                    532:                            realitexpire, p);
1.1       cgd       533:                }
                    534:                p->p_realtimer = aitv;
                    535:        } else
1.30      mycroft   536:                p->p_stats->p_timer[which] = aitv;
1.1       cgd       537:        splx(s);
                    538:        return (0);
                    539: }
                    540:
                    541: /*
                    542:  * Real interval timer expired:
                    543:  * send process whose timer expired an alarm signal.
                    544:  * If time is not set up to reload, then just return.
                    545:  * Else compute next time timer should go off which is > current time.
                    546:  * This is where delay in processing this timeout causes multiple
                    547:  * SIGALRM calls to be compressed into one.
                    548:  */
1.3       andrew    549: void
1.6       cgd       550: realitexpire(arg)
                    551:        void *arg;
                    552: {
1.45      augustss  553:        struct proc *p;
1.1       cgd       554:        int s;
                    555:
1.6       cgd       556:        p = (struct proc *)arg;
1.1       cgd       557:        psignal(p, SIGALRM);
                    558:        if (!timerisset(&p->p_realtimer.it_interval)) {
                    559:                timerclear(&p->p_realtimer.it_value);
                    560:                return;
                    561:        }
                    562:        for (;;) {
                    563:                s = splclock();
1.14      mycroft   564:                timeradd(&p->p_realtimer.it_value,
                    565:                    &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
1.1       cgd       566:                if (timercmp(&p->p_realtimer.it_value, &time, >)) {
1.44      thorpej   567:                        callout_reset(&p->p_realit_ch,
                    568:                            hzto(&p->p_realtimer.it_value), realitexpire, p);
1.1       cgd       569:                        splx(s);
                    570:                        return;
                    571:                }
                    572:                splx(s);
                    573:        }
                    574: }
                    575:
                    576: /*
                    577:  * Check that a proposed value to load into the .it_value or
                    578:  * .it_interval part of an interval timer is acceptable, and
                    579:  * fix it to have at least minimal value (i.e. if it is less
                    580:  * than the resolution of the clock, round it up.)
                    581:  */
1.3       andrew    582: int
1.1       cgd       583: itimerfix(tv)
                    584:        struct timeval *tv;
                    585: {
                    586:
                    587:        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
                    588:            tv->tv_usec < 0 || tv->tv_usec >= 1000000)
                    589:                return (EINVAL);
                    590:        if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
                    591:                tv->tv_usec = tick;
                    592:        return (0);
                    593: }
                    594:
                    595: /*
                    596:  * Decrement an interval timer by a specified number
                    597:  * of microseconds, which must be less than a second,
                    598:  * i.e. < 1000000.  If the timer expires, then reload
                    599:  * it.  In this case, carry over (usec - old value) to
1.8       cgd       600:  * reduce the value reloaded into the timer so that
1.1       cgd       601:  * the timer does not drift.  This routine assumes
                    602:  * that it is called in a context where the timers
                    603:  * on which it is operating cannot change in value.
                    604:  */
1.3       andrew    605: int
1.1       cgd       606: itimerdecr(itp, usec)
1.45      augustss  607:        struct itimerval *itp;
1.1       cgd       608:        int usec;
                    609: {
                    610:
                    611:        if (itp->it_value.tv_usec < usec) {
                    612:                if (itp->it_value.tv_sec == 0) {
                    613:                        /* expired, and already in next interval */
                    614:                        usec -= itp->it_value.tv_usec;
                    615:                        goto expire;
                    616:                }
                    617:                itp->it_value.tv_usec += 1000000;
                    618:                itp->it_value.tv_sec--;
                    619:        }
                    620:        itp->it_value.tv_usec -= usec;
                    621:        usec = 0;
                    622:        if (timerisset(&itp->it_value))
                    623:                return (1);
                    624:        /* expired, exactly at end of interval */
                    625: expire:
                    626:        if (timerisset(&itp->it_interval)) {
                    627:                itp->it_value = itp->it_interval;
                    628:                itp->it_value.tv_usec -= usec;
                    629:                if (itp->it_value.tv_usec < 0) {
                    630:                        itp->it_value.tv_usec += 1000000;
                    631:                        itp->it_value.tv_sec--;
                    632:                }
                    633:        } else
                    634:                itp->it_value.tv_usec = 0;              /* sec is already 0 */
                    635:        return (0);
1.42      cgd       636: }
                    637:
                    638: /*
                    639:  * ratecheck(): simple time-based rate-limit checking.  see ratecheck(9)
                    640:  * for usage and rationale.
                    641:  */
                    642: int
                    643: ratecheck(lasttime, mininterval)
                    644:        struct timeval *lasttime;
                    645:        const struct timeval *mininterval;
                    646: {
1.49      itojun    647:        struct timeval tv, delta;
1.42      cgd       648:        int s, rv = 0;
                    649:
                    650:        s = splclock();
1.49      itojun    651:        tv = mono_time;
                    652:        splx(s);
                    653:
                    654:        timersub(&tv, lasttime, &delta);
1.42      cgd       655:
                    656:        /*
                    657:         * check for 0,0 is so that the message will be seen at least once,
                    658:         * even if interval is huge.
                    659:         */
                    660:        if (timercmp(&delta, mininterval, >=) ||
                    661:            (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
1.49      itojun    662:                *lasttime = tv;
1.42      cgd       663:                rv = 1;
                    664:        }
1.50    ! itojun    665:
        !           666:        return (rv);
        !           667: }
        !           668:
        !           669: /*
        !           670:  * ppsratecheck(): packets (or events) per second limitation.
        !           671:  */
        !           672: int
        !           673: ppsratecheck(lasttime, curpps, maxpps)
        !           674:        struct timeval *lasttime;
        !           675:        int *curpps;
        !           676:        int maxpps;     /* maximum pps allowed */
        !           677: {
        !           678:        struct timeval tv, delta;
        !           679:        int s, rv;
        !           680:
        !           681:        s = splclock();
        !           682:        tv = mono_time;
        !           683:        splx(s);
        !           684:
        !           685:        timersub(&tv, lasttime, &delta);
        !           686:
        !           687:        /*
        !           688:         * check for 0,0 is so that the message will be seen at least once.
        !           689:         * if more than one second have passed since the last update of
        !           690:         * lasttime, reset the counter.
        !           691:         *
        !           692:         * we do increment *curpps even in *curpps < maxpps case, as some may
        !           693:         * try to use *curpps for stat purposes as well.
        !           694:         */
        !           695:        if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
        !           696:            delta.tv_sec >= 1) {
        !           697:                *lasttime = tv;
        !           698:                *curpps = 0;
        !           699:                rv = 1;
        !           700:        } else if (*curpps < maxpps)
        !           701:                rv = 1;
        !           702:        else
        !           703:                rv = 0;
        !           704:
        !           705: #if 1 /*DIAGNOSTICS?*/
        !           706:        /* be careful about wrap-around */
        !           707:        if (*curpps + 1 > *curpps)
        !           708:                *curpps = *curpps + 1;
        !           709: #else
        !           710:        /*
        !           711:         * assume that there's not too many calls to this function.
        !           712:         * not sure if the assumption holds, as it depends on *caller's*
        !           713:         * behavior, not the behavior of this function.
        !           714:         * IMHO it is wrong to make assumption on the caller's behavior,
        !           715:         * so the above #if is #if 1, not #ifdef DIAGNOSTICS.
        !           716:         */
        !           717:        *curpps = *curpps + 1;
        !           718: #endif
1.42      cgd       719:
                    720:        return (rv);
1.1       cgd       721: }

CVSweb <webmaster@jp.NetBSD.org>