|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)kern_time.c 7.15 (Berkeley) 3/17/91 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "resourcevar.h" ! 38: #include "kernel.h" ! 39: #include "proc.h" ! 40: ! 41: #include "machine/cpu.h" ! 42: ! 43: /* ! 44: * Time of day and interval timer support. ! 45: * ! 46: * These routines provide the kernel entry points to get and set ! 47: * the time-of-day and per-process interval timers. Subroutines ! 48: * here provide support for adding and subtracting timeval structures ! 49: * and decrementing interval timers, optionally reloading the interval ! 50: * timers when they expire. ! 51: */ ! 52: ! 53: /* ARGSUSED */ ! 54: gettimeofday(p, uap, retval) ! 55: struct proc *p; ! 56: register struct args { ! 57: struct timeval *tp; ! 58: struct timezone *tzp; ! 59: } *uap; ! 60: int *retval; ! 61: { ! 62: struct timeval atv; ! 63: int error = 0; ! 64: ! 65: if (uap->tp) { ! 66: microtime(&atv); ! 67: if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp, ! 68: sizeof (atv))) ! 69: return (error); ! 70: } ! 71: if (uap->tzp) ! 72: error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, ! 73: sizeof (tz)); ! 74: return (error); ! 75: } ! 76: ! 77: /* ARGSUSED */ ! 78: settimeofday(p, uap, retval) ! 79: struct proc *p; ! 80: struct args { ! 81: struct timeval *tv; ! 82: struct timezone *tzp; ! 83: } *uap; ! 84: int *retval; ! 85: { ! 86: struct timeval atv; ! 87: struct timezone atz; ! 88: int error, s; ! 89: ! 90: if (error = suser(p->p_ucred, &p->p_acflag)) ! 91: return (error); ! 92: if (uap->tv) { ! 93: if (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, ! 94: sizeof (struct timeval))) ! 95: return (error); ! 96: /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ ! 97: boottime.tv_sec += atv.tv_sec - time.tv_sec; ! 98: s = splhigh(); time = atv; splx(s); ! 99: resettodr(); ! 100: } ! 101: if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, ! 102: sizeof (atz))) == 0) ! 103: tz = atz; ! 104: return (error); ! 105: } ! 106: ! 107: extern int tickadj; /* "standard" clock skew, us./tick */ ! 108: int tickdelta; /* current clock skew, us. per tick */ ! 109: long timedelta; /* unapplied time correction, us. */ ! 110: long bigadj = 1000000; /* use 10x skew above bigadj us. */ ! 111: ! 112: /* ARGSUSED */ ! 113: adjtime(p, uap, retval) ! 114: struct proc *p; ! 115: register struct args { ! 116: struct timeval *delta; ! 117: struct timeval *olddelta; ! 118: } *uap; ! 119: int *retval; ! 120: { ! 121: struct timeval atv, oatv; ! 122: register long ndelta; ! 123: int s, error; ! 124: ! 125: if (error = suser(p->p_ucred, &p->p_acflag)) ! 126: return (error); ! 127: if (error = ! 128: copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof (struct timeval))) ! 129: return (error); ! 130: ndelta = atv.tv_sec * 1000000 + atv.tv_usec; ! 131: if (timedelta == 0) ! 132: if (ndelta > bigadj) ! 133: tickdelta = 10 * tickadj; ! 134: else ! 135: tickdelta = tickadj; ! 136: if (ndelta % tickdelta) ! 137: ndelta = ndelta / tickadj * tickadj; ! 138: ! 139: s = splclock(); ! 140: if (uap->olddelta) { ! 141: oatv.tv_sec = timedelta / 1000000; ! 142: oatv.tv_usec = timedelta % 1000000; ! 143: } ! 144: timedelta = ndelta; ! 145: splx(s); ! 146: ! 147: if (uap->olddelta) ! 148: (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta, ! 149: sizeof (struct timeval)); ! 150: return (0); ! 151: } ! 152: ! 153: /* ! 154: * Get value of an interval timer. The process virtual and ! 155: * profiling virtual time timers are kept in the p_stats area, since ! 156: * they can be swapped out. These are kept internally in the ! 157: * way they are specified externally: in time until they expire. ! 158: * ! 159: * The real time interval timer is kept in the process table slot ! 160: * for the process, and its value (it_value) is kept as an ! 161: * absolute time rather than as a delta, so that it is easy to keep ! 162: * periodic real-time signals from drifting. ! 163: * ! 164: * Virtual time timers are processed in the hardclock() routine of ! 165: * kern_clock.c. The real time timer is processed by a timeout ! 166: * routine, called from the softclock() routine. Since a callout ! 167: * may be delayed in real time due to interrupt processing in the system, ! 168: * it is possible for the real time timeout routine (realitexpire, given below), ! 169: * to be delayed in real time past when it is supposed to occur. It ! 170: * does not suffice, therefore, to reload the real timer .it_value from the ! 171: * real time timers .it_interval. Rather, we compute the next time in ! 172: * absolute time the timer should go off. ! 173: */ ! 174: /* ARGSUSED */ ! 175: getitimer(p, uap, retval) ! 176: struct proc *p; ! 177: register struct args { ! 178: u_int which; ! 179: struct itimerval *itv; ! 180: } *uap; ! 181: int *retval; ! 182: { ! 183: struct itimerval aitv; ! 184: int s; ! 185: ! 186: if (uap->which > ITIMER_PROF) ! 187: return (EINVAL); ! 188: s = splclock(); ! 189: if (uap->which == ITIMER_REAL) { ! 190: /* ! 191: * Convert from absoulte to relative time in .it_value ! 192: * part of real time timer. If time for real time timer ! 193: * has passed return 0, else return difference between ! 194: * current time and time for the timer to go off. ! 195: */ ! 196: aitv = p->p_realtimer; ! 197: if (timerisset(&aitv.it_value)) ! 198: if (timercmp(&aitv.it_value, &time, <)) ! 199: timerclear(&aitv.it_value); ! 200: else ! 201: timevalsub(&aitv.it_value, &time); ! 202: } else ! 203: aitv = p->p_stats->p_timer[uap->which]; ! 204: splx(s); ! 205: return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, ! 206: sizeof (struct itimerval))); ! 207: } ! 208: ! 209: /* ARGSUSED */ ! 210: setitimer(p, uap, retval) ! 211: struct proc *p; ! 212: register struct args { ! 213: u_int which; ! 214: struct itimerval *itv, *oitv; ! 215: } *uap; ! 216: int *retval; ! 217: { ! 218: struct itimerval aitv; ! 219: register struct itimerval *itvp; ! 220: int s, error; ! 221: ! 222: if (uap->which > ITIMER_PROF) ! 223: return (EINVAL); ! 224: itvp = uap->itv; ! 225: if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, ! 226: sizeof(struct itimerval)))) ! 227: return (error); ! 228: if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval))) ! 229: return (error); ! 230: if (itvp == 0) ! 231: return (0); ! 232: if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) ! 233: return (EINVAL); ! 234: s = splclock(); ! 235: if (uap->which == ITIMER_REAL) { ! 236: untimeout(realitexpire, (caddr_t)p); ! 237: if (timerisset(&aitv.it_value)) { ! 238: timevaladd(&aitv.it_value, &time); ! 239: timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); ! 240: } ! 241: p->p_realtimer = aitv; ! 242: } else ! 243: p->p_stats->p_timer[uap->which] = aitv; ! 244: splx(s); ! 245: return (0); ! 246: } ! 247: ! 248: /* ! 249: * Real interval timer expired: ! 250: * send process whose timer expired an alarm signal. ! 251: * If time is not set up to reload, then just return. ! 252: * Else compute next time timer should go off which is > current time. ! 253: * This is where delay in processing this timeout causes multiple ! 254: * SIGALRM calls to be compressed into one. ! 255: */ ! 256: realitexpire(p) ! 257: register struct proc *p; ! 258: { ! 259: int s; ! 260: ! 261: psignal(p, SIGALRM); ! 262: if (!timerisset(&p->p_realtimer.it_interval)) { ! 263: timerclear(&p->p_realtimer.it_value); ! 264: return; ! 265: } ! 266: for (;;) { ! 267: s = splclock(); ! 268: timevaladd(&p->p_realtimer.it_value, ! 269: &p->p_realtimer.it_interval); ! 270: if (timercmp(&p->p_realtimer.it_value, &time, >)) { ! 271: timeout(realitexpire, (caddr_t)p, ! 272: hzto(&p->p_realtimer.it_value)); ! 273: splx(s); ! 274: return; ! 275: } ! 276: splx(s); ! 277: } ! 278: } ! 279: ! 280: /* ! 281: * Check that a proposed value to load into the .it_value or ! 282: * .it_interval part of an interval timer is acceptable, and ! 283: * fix it to have at least minimal value (i.e. if it is less ! 284: * than the resolution of the clock, round it up.) ! 285: */ ! 286: itimerfix(tv) ! 287: struct timeval *tv; ! 288: { ! 289: ! 290: if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || ! 291: tv->tv_usec < 0 || tv->tv_usec >= 1000000) ! 292: return (EINVAL); ! 293: if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) ! 294: tv->tv_usec = tick; ! 295: return (0); ! 296: } ! 297: ! 298: /* ! 299: * Decrement an interval timer by a specified number ! 300: * of microseconds, which must be less than a second, ! 301: * i.e. < 1000000. If the timer expires, then reload ! 302: * it. In this case, carry over (usec - old value) to ! 303: * reducint the value reloaded into the timer so that ! 304: * the timer does not drift. This routine assumes ! 305: * that it is called in a context where the timers ! 306: * on which it is operating cannot change in value. ! 307: */ ! 308: itimerdecr(itp, usec) ! 309: register struct itimerval *itp; ! 310: int usec; ! 311: { ! 312: ! 313: if (itp->it_value.tv_usec < usec) { ! 314: if (itp->it_value.tv_sec == 0) { ! 315: /* expired, and already in next interval */ ! 316: usec -= itp->it_value.tv_usec; ! 317: goto expire; ! 318: } ! 319: itp->it_value.tv_usec += 1000000; ! 320: itp->it_value.tv_sec--; ! 321: } ! 322: itp->it_value.tv_usec -= usec; ! 323: usec = 0; ! 324: if (timerisset(&itp->it_value)) ! 325: return (1); ! 326: /* expired, exactly at end of interval */ ! 327: expire: ! 328: if (timerisset(&itp->it_interval)) { ! 329: itp->it_value = itp->it_interval; ! 330: itp->it_value.tv_usec -= usec; ! 331: if (itp->it_value.tv_usec < 0) { ! 332: itp->it_value.tv_usec += 1000000; ! 333: itp->it_value.tv_sec--; ! 334: } ! 335: } else ! 336: itp->it_value.tv_usec = 0; /* sec is already 0 */ ! 337: return (0); ! 338: } ! 339: ! 340: /* ! 341: * Add and subtract routines for timevals. ! 342: * N.B.: subtract routine doesn't deal with ! 343: * results which are before the beginning, ! 344: * it just gets very confused in this case. ! 345: * Caveat emptor. ! 346: */ ! 347: timevaladd(t1, t2) ! 348: struct timeval *t1, *t2; ! 349: { ! 350: ! 351: t1->tv_sec += t2->tv_sec; ! 352: t1->tv_usec += t2->tv_usec; ! 353: timevalfix(t1); ! 354: } ! 355: ! 356: timevalsub(t1, t2) ! 357: struct timeval *t1, *t2; ! 358: { ! 359: ! 360: t1->tv_sec -= t2->tv_sec; ! 361: t1->tv_usec -= t2->tv_usec; ! 362: timevalfix(t1); ! 363: } ! 364: ! 365: timevalfix(t1) ! 366: struct timeval *t1; ! 367: { ! 368: ! 369: if (t1->tv_usec < 0) { ! 370: t1->tv_sec--; ! 371: t1->tv_usec += 1000000; ! 372: } ! 373: if (t1->tv_usec >= 1000000) { ! 374: t1->tv_sec++; ! 375: t1->tv_usec -= 1000000; ! 376: } ! 377: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.