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