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