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