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