Annotation of kernel/bsd/kern/kern_time.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     26: /*
                     27:  * Copyright (c) 1982, 1986, 1989, 1993
                     28:  *     The Regents of the University of California.  All rights reserved.
                     29:  *
                     30:  * Redistribution and use in source and binary forms, with or without
                     31:  * modification, are permitted provided that the following conditions
                     32:  * are met:
                     33:  * 1. Redistributions of source code must retain the above copyright
                     34:  *    notice, this list of conditions and the following disclaimer.
                     35:  * 2. Redistributions in binary form must reproduce the above copyright
                     36:  *    notice, this list of conditions and the following disclaimer in the
                     37:  *    documentation and/or other materials provided with the distribution.
                     38:  * 3. All advertising materials mentioning features or use of this software
                     39:  *    must display the following acknowledgement:
                     40:  *     This product includes software developed by the University of
                     41:  *     California, Berkeley and its contributors.
                     42:  * 4. Neither the name of the University nor the names of its contributors
                     43:  *    may be used to endorse or promote products derived from this software
                     44:  *    without specific prior written permission.
                     45:  *
                     46:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     47:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     48:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     49:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     50:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     51:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     52:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     53:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     54:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     55:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     56:  * SUCH DAMAGE.
                     57:  *
                     58:  *     @(#)kern_time.c 8.4 (Berkeley) 5/26/95
                     59:  */
                     60: 
                     61: #include <sys/param.h>
                     62: #include <sys/resourcevar.h>
                     63: #include <sys/kernel.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/proc.h>
                     66: #include <sys/vnode.h>
                     67: 
                     68: #include <sys/mount.h>
                     69: 
                     70: #include <machine/cpu.h>
                     71: 
                     72: #include <kern/clock.h>
                     73: 
                     74: /* 
                     75:  * Time of day and interval timer support.
                     76:  *
                     77:  * These routines provide the kernel entry points to get and set
                     78:  * the time-of-day and per-process interval timers.  Subroutines
                     79:  * here provide support for adding and subtracting timeval structures
                     80:  * and decrementing interval timers, optionally reloading the interval
                     81:  * timers when they expire.
                     82:  */
                     83: struct gettimeofday_args{
                     84:        struct timeval *tp;
                     85:        struct timezone *tzp;
                     86: };
                     87: /* ARGSUSED */
                     88: int
                     89: gettimeofday(p, uap, retval)
                     90:        struct proc *p;
                     91:        register struct gettimeofday_args *uap;
                     92:        register_t *retval;
                     93: {
                     94:        struct timeval atv;
                     95:        int error = 0;
                     96: 
                     97:        if (uap->tp) {
                     98:                microtime(&atv);
                     99:                if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
                    100:                        sizeof (atv)))
                    101:                        return(error);
                    102:        }
                    103:        
                    104:        if (uap->tzp)
                    105:                error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
                    106:                    sizeof (tz));
                    107: 
                    108:        return(error);
                    109: }
                    110: 
                    111: struct settimeofday_args {
                    112:        struct timeval *tv;
                    113:        struct timezone *tzp;
                    114: };
                    115: /* ARGSUSED */
                    116: int
                    117: settimeofday(p, uap, retval)
                    118:        struct proc *p;
                    119:        struct settimeofday_args  *uap;
                    120:        register_t *retval;
                    121: {
                    122:        struct timeval atv;
                    123:        struct timezone atz;
                    124:        int error, s;
                    125: 
                    126:        if (error = suser(p->p_ucred, &p->p_acflag))
                    127:                return (error);
                    128:        /* Verify all parameters before changing time. */
                    129:        if (uap->tv && (error = copyin((caddr_t)uap->tv,
                    130:            (caddr_t)&atv, sizeof(atv))))
                    131:                return (error);
                    132:        if (uap->tzp && (error = copyin((caddr_t)uap->tzp,
                    133:            (caddr_t)&atz, sizeof(atz))))
                    134:                return (error);
                    135:        if (uap->tv) {
                    136:                error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
                    137:                        sizeof (struct timeval));
                    138:                if (error)
                    139:                        return(error);
                    140:                setthetime(&atv);
                    141:        }
                    142:        if (uap->tzp)
                    143:                tz = atz;
                    144:        return (0);
                    145: }
                    146: 
                    147: setthetime(tv)
                    148:        struct timeval *tv;
                    149: {
                    150:        tvalspec_t      now;
                    151:        long delta;
                    152:        int s;
                    153:                
                    154:        now.tv_sec = tv->tv_sec;
                    155:        now.tv_nsec = tv->tv_usec * NSEC_PER_USEC;
                    156: 
                    157:        clock_set_counter(Calendar, now);
                    158:        delta = tv->tv_sec - time.tv_sec;
                    159:        boottime.tv_sec += delta;
                    160: #if NFSCLIENT || NFSSERVER
                    161:        lease_updatetime(delta);
                    162: #endif
                    163:        s = splhigh();
                    164:        microtime(&time);
                    165:        splx(s);
                    166: }
                    167: 
                    168: int    tickadj = 240000 / (60 * HZ);   /* "standard" clock skew, us./tick */
                    169: int    tickdelta;                      /* current clock skew, us. per tick */
                    170: long   timedelta;                      /* unapplied time correction, us. */
                    171: long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
                    172: 
                    173: 
                    174: struct adjtime_args {
                    175:        struct timeval *delta;
                    176:        struct timeval *olddelta;
                    177: };
                    178: /* ARGSUSED */
                    179: int
                    180: adjtime(p, uap, retval)
                    181:        struct proc *p;
                    182:        register struct adjtime_args *uap;
                    183:        register_t *retval;
                    184: {
                    185:        struct timeval atv, oatv;
                    186:        register long ndelta;
                    187:        int s, error;
                    188: 
                    189:        if (error = suser(p->p_ucred, &p->p_acflag))
                    190:                return (error);
                    191:        if(error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
                    192:                sizeof (struct timeval)))
                    193:                return(error);
                    194:                
                    195:        ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
                    196:        if (timedelta == 0)
                    197:                if (ndelta > bigadj)
                    198:                        tickdelta = 10 * tickadj;
                    199:                else
                    200:                        tickdelta = tickadj;
                    201:        if (ndelta % tickdelta)
                    202:                ndelta = ndelta / tickdelta * tickdelta;
                    203: 
                    204:        s = splclock();
                    205:        if (uap->olddelta) {
                    206:                oatv.tv_sec = timedelta / 1000000;
                    207:                oatv.tv_usec = timedelta % 1000000;
                    208:        }
                    209:        timedelta = ndelta;
                    210:        splx(s);
                    211: 
                    212:        if (uap->olddelta)
                    213:                (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
                    214:                        sizeof (struct timeval));
                    215:        return(0);
                    216: }
                    217: 
                    218: #define SECDAY          ((unsigned)(24*60*60))          /* seconds per day */
                    219: #define SECYR           ((unsigned)(365*SECDAY))        /* per common year */
                    220: #define YRREF           70      /* UNIX time referenced to 1970 */
                    221: 
                    222: /*
                    223:  * Initialze the time of day register, based on the time base which is, e.g.
                    224:  * from a filesystem.
                    225:  */
                    226: void
                    227: inittodr(base)
                    228:        time_t base;
                    229: {
                    230:        long deltat;
                    231: 
                    232:        if (base < (87-YRREF) * SECYR || base < 0) {    /* fs < than 1987? */
                    233:                printf("WARNING: preposterous time in file system");
                    234:                goto check;
                    235:        }
                    236: 
                    237:        /*
                    238:         * The value returned by microtime()
                    239:         * is gotten from the 'Calendar' clock.
                    240:         * It is initialized from the RTC early
                    241:         * on during system intialization, so
                    242:         * that it contains a useful value at this
                    243:         * point.
                    244:         */
                    245:        microtime(&time);
                    246: 
                    247:        /*
                    248:         * This variable still exists to keep
                    249:         * 'w' happy.  It should only be considered
                    250:         * an approximation.
                    251:         */
                    252:        boottime.tv_sec = time.tv_sec;
                    253:        boottime.tv_usec = 0;
                    254: 
                    255:        /*
                    256:         * See if we gained/lost two or more days;
                    257:         * if so, assume something is amiss.
                    258:         * Avoid changing RTC if RTC time > file system time and delta is
                    259:         * less than two days.
                    260:         */
                    261:        deltat = time.tv_sec - base;
                    262:        if (deltat < 0)
                    263:                deltat = -deltat;
                    264:        if ((deltat < 2*SECDAY) && (time.tv_sec > base))
                    265:                return;
                    266:        if (time.tv_sec < SECYR) {
                    267:                printf ("WARNING: clock not set properly");
                    268:                time.tv_sec = base;
                    269:                time.tv_usec = 0;
                    270:                setthetime(&time);
                    271:                boottime = time;
                    272:                goto check;
                    273:        }
                    274: 
                    275:        if (deltat > 90*SECDAY) {       /* assume rtc is way off */
                    276:                printf ("WARNING: preposterous time in Real Time Clock");
                    277:                time.tv_sec = base;
                    278:                time.tv_usec = 0;
                    279:                setthetime(&time);
                    280:                boottime = time;
                    281:                goto check;
                    282:        }
                    283:        printf("WARNING: clock lost %d days", deltat / SECDAY);
                    284: check:
                    285:        printf(" -- CHECK AND RESET THE DATE!\n");
                    286: }
                    287: 
                    288: /*
                    289:  * Get value of an interval timer.  The process virtual and
                    290:  * profiling virtual time timers are kept in the u. area, since
                    291:  * they can be swapped out.  These are kept internally in the
                    292:  * way they are specified externally: in time until they expire.
                    293:  *
                    294:  * The real time interval timer is kept in the process table slot
                    295:  * for the process, and its value (it_value) is kept as an
                    296:  * absolute time rather than as a delta, so that it is easy to keep
                    297:  * periodic real-time signals from drifting.
                    298:  *
                    299:  * Virtual time timers are processed in the hardclock() routine of
                    300:  * kern_clock.c.  The real time timer is processed by a timeout
                    301:  * routine, called from the softclock() routine.  Since a callout
                    302:  * may be delayed in real time due to interrupt processing in the system,
                    303:  * it is possible for the real time timeout routine (realitexpire, given below),
                    304:  * to be delayed in real time past when it is supposed to occur.  It
                    305:  * does not suffice, therefore, to reload the real timer .it_value from the
                    306:  * real time timers .it_interval.  Rather, we compute the next time in
                    307:  * absolute time the timer should go off.
                    308:  */
                    309:  
                    310: struct getitimer_args {
                    311:        u_int   which;
                    312:        struct itimerval *itv;
                    313: }; 
                    314: /* ARGSUSED */
                    315: int
                    316: getitimer(p, uap, retval)
                    317:        struct proc *p;
                    318:        register struct getitimer_args *uap;
                    319:        register_t *retval;
                    320: {
                    321:        struct itimerval aitv;
                    322:        int s;
                    323: 
                    324:        if (uap->which > ITIMER_PROF)
                    325:                return(EINVAL);
                    326:        
                    327:        s = splclock();
                    328:        if (uap->which == ITIMER_REAL) {
                    329:                /*
                    330:                 * Convert from absoulte to relative time in .it_value
                    331:                 * part of real time timer.  If time for real time timer
                    332:                 * has passed return 0, else return difference between
                    333:                 * current time and time for the timer to go off.
                    334:                 */
                    335:                aitv = p->p_realtimer;
                    336:                if (timerisset(&aitv.it_value))
                    337:                        if (timercmp(&aitv.it_value, &time, <))
                    338:                                timerclear(&aitv.it_value);
                    339:                        else
                    340:                                timevalsub(&aitv.it_value, &time);
                    341:        } else
                    342:                aitv =p->p_stats->p_timer[uap->which];
                    343:        splx(s);
                    344:        return(copyout((caddr_t)&aitv, (caddr_t)uap->itv,
                    345:            sizeof (struct itimerval)));
                    346: }
                    347: 
                    348: struct setitimer_args {
                    349:        u_int   which;
                    350:        struct  itimerval *itv;
                    351:        struct  itimerval *oitv;
                    352: };
                    353: /* ARGSUSED */
                    354: int
                    355: setitimer(p, uap, retval)
                    356:        struct proc *p;
                    357:        register struct setitimer_args *uap;
                    358:        register_t *retval;
                    359: {
                    360:        struct itimerval aitv;
                    361:        register struct itimerval *itvp;
                    362:        int s, error;
                    363: 
                    364:        if (uap->which > ITIMER_PROF)
                    365:                return(EINVAL);
                    366:        itvp = uap->itv;
                    367:        if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
                    368:            sizeof(struct itimerval))))
                    369:                return (error);
                    370:        if ((uap->itv = uap->oitv) &&
                    371:            (error = getitimer(p, uap, retval)))
                    372:                return (error);
                    373:        if (itvp == 0)
                    374:                return (0);
                    375:        if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
                    376:                return (EINVAL);
                    377:        s = splclock();
                    378:        if (uap->which == ITIMER_REAL) {
                    379:                untimeout(realitexpire, (caddr_t)p);
                    380:                if (timerisset(&aitv.it_value)) {
                    381:                        timevaladd(&aitv.it_value, &time);
                    382:                        timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
                    383:                }
                    384:                p->p_realtimer = aitv;
                    385:        } else
                    386:                p->p_stats->p_timer[uap->which] = aitv;
                    387:        splx(s);
                    388:        return(0); /* To insure good return value on success */
                    389: }
                    390: 
                    391: /*
                    392:  * Real interval timer expired:
                    393:  * send process whose timer expired an alarm signal.
                    394:  * If time is not set up to reload, then just return.
                    395:  * Else compute next time timer should go off which is > current time.
                    396:  * This is where delay in processing this timeout causes multiple
                    397:  * SIGALRM calls to be compressed into one.
                    398:  */
                    399: void
                    400: realitexpire(arg)
                    401:        void *arg;
                    402: {
                    403:        register struct proc *p;
                    404:        int s;
                    405: 
                    406:        p = (struct proc *)arg;
                    407:        psignal(p, SIGALRM);
                    408:        if (!timerisset(&p->p_realtimer.it_interval)) {
                    409:                timerclear(&p->p_realtimer.it_value);
                    410:                return;
                    411:        }
                    412:        
                    413:        /*
                    414:         * If the time's way off, don't try to compensate by getting
                    415:         * there incrementally.
                    416:         */
                    417:        s = splclock();
                    418:        if (p->p_realtimer.it_value.tv_sec < time.tv_sec - 10) {
                    419:                p->p_realtimer.it_value = time;
                    420:                timeout(realitexpire, (caddr_t)p,
                    421:                        hzto(&p->p_realtimer.it_value));
                    422:                splx(s);
                    423:                return;
                    424:                
                    425:        }
                    426:        splx(s);
                    427: 
                    428:        for (;;) {
                    429:                s = splclock();
                    430:                timevaladd(&p->p_realtimer.it_value,
                    431:                    &p->p_realtimer.it_interval);
                    432:                if (timercmp(&p->p_realtimer.it_value, &time, >)) {
                    433:                        timeout(realitexpire, (caddr_t)p,
                    434:                            hzto(&p->p_realtimer.it_value));
                    435:                        splx(s);
                    436:                        return;
                    437:                }
                    438:                splx(s);
                    439:        }
                    440: }
                    441: 
                    442: /*
                    443:  * Check that a proposed value to load into the .it_value or
                    444:  * .it_interval part of an interval timer is acceptable, and
                    445:  * fix it to have at least minimal value (i.e. if it is less
                    446:  * than the resolution of the clock, round it up.)
                    447:  */
                    448: int
                    449: itimerfix(tv)
                    450:        struct timeval *tv;
                    451: {
                    452: 
                    453:        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
                    454:            tv->tv_usec < 0 || tv->tv_usec >= 1000000)
                    455:                return (EINVAL);
                    456:        if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
                    457:                tv->tv_usec = tick;
                    458:        return (0);
                    459: }
                    460: 
                    461: /*
                    462:  * Decrement an interval timer by a specified number
                    463:  * of microseconds, which must be less than a second,
                    464:  * i.e. < 1000000.  If the timer expires, then reload
                    465:  * it.  In this case, carry over (usec - old value) to
                    466:  * reducint the value reloaded into the timer so that
                    467:  * the timer does not drift.  This routine assumes
                    468:  * that it is called in a context where the timers
                    469:  * on which it is operating cannot change in value.
                    470:  */
                    471: int
                    472: itimerdecr(itp, usec)
                    473:        register struct itimerval *itp;
                    474:        int usec;
                    475: {
                    476: 
                    477:        if (itp->it_value.tv_usec < usec) {
                    478:                if (itp->it_value.tv_sec == 0) {
                    479:                        /* expired, and already in next interval */
                    480:                        usec -= itp->it_value.tv_usec;
                    481:                        goto expire;
                    482:                }
                    483:                itp->it_value.tv_usec += 1000000;
                    484:                itp->it_value.tv_sec--;
                    485:        }
                    486:        itp->it_value.tv_usec -= usec;
                    487:        usec = 0;
                    488:        if (timerisset(&itp->it_value))
                    489:                return (1);
                    490:        /* expired, exactly at end of interval */
                    491: expire:
                    492:        if (timerisset(&itp->it_interval)) {
                    493:                itp->it_value = itp->it_interval;
                    494:                itp->it_value.tv_usec -= usec;
                    495:                if (itp->it_value.tv_usec < 0) {
                    496:                        itp->it_value.tv_usec += 1000000;
                    497:                        itp->it_value.tv_sec--;
                    498:                }
                    499:        } else
                    500:                itp->it_value.tv_usec = 0;              /* sec is already 0 */
                    501:        return (0);
                    502: }
                    503: 
                    504: /*
                    505:  * Add and subtract routines for timevals.
                    506:  * N.B.: subtract routine doesn't deal with
                    507:  * results which are before the beginning,
                    508:  * it just gets very confused in this case.
                    509:  * Caveat emptor.
                    510:  */
                    511: timevaladd(t1, t2)
                    512:        struct timeval *t1, *t2;
                    513: {
                    514: 
                    515:        t1->tv_sec += t2->tv_sec;
                    516:        t1->tv_usec += t2->tv_usec;
                    517:        timevalfix(t1);
                    518: }
                    519: 
                    520: timevalsub(t1, t2)
                    521:        struct timeval *t1, *t2;
                    522: {
                    523: 
                    524:        t1->tv_sec -= t2->tv_sec;
                    525:        t1->tv_usec -= t2->tv_usec;
                    526:        timevalfix(t1);
                    527: }
                    528: 
                    529: timevalfix(t1)
                    530:        struct timeval *t1;
                    531: {
                    532: 
                    533:        if (t1->tv_usec < 0) {
                    534:                t1->tv_sec--;
                    535:                t1->tv_usec += 1000000;
                    536:        }
                    537:        if (t1->tv_usec >= 1000000) {
                    538:                t1->tv_sec++;
                    539:                t1->tv_usec -= 1000000;
                    540:        }
                    541: }
                    542: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.