|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.