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