1 /* kern_time.c 5.12 82/12/17 */ 2 3 #include "../machine/reg.h" 4 5 #include "../h/param.h" 6 #include "../h/dir.h" /* XXX */ 7 #include "../h/user.h" 8 #include "../h/kernel.h" 9 #include "../h/inode.h" 10 #include "../h/proc.h" 11 12 /* 13 * Time of day and interval timer support. 14 * 15 * These routines provide the kernel entry points to get and set 16 * the time-of-day and per-process interval timers. Subroutines 17 * here provide support for adding and subtracting timeval structures 18 * and decrementing interval timers, optionally reloading the interval 19 * timers when they expire. 20 */ 21 22 gettimeofday() 23 { 24 register struct a { 25 struct timeval *tp; 26 struct timezone *tzp; 27 } *uap = (struct a *)u.u_ap; 28 struct timeval atv; 29 int s; 30 31 s = spl7(); atv = time; splx(s); 32 if (copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv))) { 33 u.u_error = EFAULT; 34 return; 35 } 36 if (uap->tzp == 0) 37 return; 38 /* SHOULD HAVE PER-PROCESS TIMEZONE */ 39 if (copyout((caddr_t)&tz, (caddr_t)uap->tzp, sizeof (tz))) { 40 u.u_error = EFAULT; 41 return; 42 } 43 } 44 45 settimeofday() 46 { 47 register struct a { 48 struct timeval *tv; 49 struct timezone *tzp; 50 } *uap = (struct a *)u.u_ap; 51 struct timeval atv; 52 struct timezone atz; 53 54 if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (struct timeval))) { 55 u.u_error = EFAULT; 56 return; 57 } 58 setthetime(&atv); 59 if (uap->tzp && suser()) { 60 if (copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz))) { 61 u.u_error = EFAULT; 62 return; 63 } 64 } 65 } 66 67 setthetime(tv) 68 struct timeval *tv; 69 { 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 resettodr(); 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, (caddr_t)uap->itv, 132 sizeof (struct itimerval))) 133 u.u_error = EFAULT; 134 splx(s); 135 } 136 137 setitimer() 138 { 139 register struct a { 140 u_int which; 141 struct itimerval *itv, *oitv; 142 } *uap = (struct a *)u.u_ap; 143 struct itimerval aitv; 144 int s; 145 register struct proc *p = u.u_procp; 146 147 if (uap->which > 2) { 148 u.u_error = EINVAL; 149 return; 150 } 151 if (copyin((caddr_t)uap->itv, (caddr_t)&aitv, 152 sizeof (struct itimerval))) { 153 u.u_error = EFAULT; 154 return; 155 } 156 if (uap->oitv) { 157 uap->itv = uap->oitv; 158 getitimer(); 159 } 160 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) { 161 u.u_error = EINVAL; 162 return; 163 } 164 s = spl7(); 165 if (uap->which == ITIMER_REAL) { 166 untimeout(realitexpire, (caddr_t)p); 167 if (timerisset(&aitv.it_value)) { 168 timevaladd(&aitv.it_value, &time); 169 timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 170 } 171 p->p_realtimer = aitv; 172 } else 173 u.u_timer[uap->which] = aitv; 174 splx(s); 175 } 176 177 /* 178 * Real interval timer expired: 179 * send process whose timer expired an alarm signal. 180 * If time is not set up to reload, then just return. 181 * Else compute next time timer should go off which is > current time. 182 * This is where delay in processing this timeout causes multiple 183 * SIGALRM calls to be compressed into one. 184 */ 185 realitexpire(p) 186 register struct proc *p; 187 { 188 int s; 189 190 psignal(p, SIGALRM); 191 if (!timerisset(&p->p_realtimer.it_interval)) { 192 timerclear(&p->p_realtimer.it_value); 193 return; 194 } 195 for (;;) { 196 s = spl7(); 197 timevaladd(&p->p_realtimer.it_value, 198 &p->p_realtimer.it_interval); 199 if (timercmp(&p->p_realtimer.it_value, &time, >)) { 200 timeout(realitexpire, (caddr_t)p, 201 hzto(&p->p_realtimer.it_value)); 202 splx(s); 203 return; 204 } 205 splx(s); 206 } 207 } 208 209 /* 210 * Check that a proposed value to load into the .it_value or 211 * .it_interval part of an interval timer is acceptable, and 212 * fix it to have at least minimal value (i.e. if it is less 213 * than the resolution of the clock, round it up.) 214 */ 215 itimerfix(tv) 216 struct timeval *tv; 217 { 218 219 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 220 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 221 return (EINVAL); 222 if (tv->tv_sec == 0 && tv->tv_usec < tick) 223 tv->tv_usec = tick; 224 return (0); 225 } 226 227 /* 228 * Decrement an interval timer by a specified number 229 * of microseconds, which must be less than a second, 230 * i.e. < 1000000. If the timer expires, then reload 231 * it. In this case, carry over (usec - old value) to 232 * reducint the value reloaded into the timer so that 233 * the timer does not drift. This routine assumes 234 * that it is called in a context where the timers 235 * on which it is operating cannot change in value. 236 */ 237 itimerdecr(itp, usec) 238 register struct itimerval *itp; 239 int usec; 240 { 241 242 if (itp->it_value.tv_usec < usec) { 243 if (itp->it_value.tv_sec == 0) { 244 /* expired, and already in next interval */ 245 usec -= itp->it_value.tv_usec; 246 goto expire; 247 } 248 itp->it_value.tv_usec += 1000000; 249 itp->it_value.tv_sec--; 250 } 251 itp->it_value.tv_usec -= usec; 252 usec = 0; 253 if (timerisset(&itp->it_value)) 254 return (1); 255 /* expired, exactly at end of interval */ 256 expire: 257 if (timerisset(&itp->it_interval)) { 258 itp->it_value = itp->it_interval; 259 itp->it_value.tv_usec -= usec; 260 if (itp->it_value.tv_usec < 0) { 261 itp->it_value.tv_usec += 1000000; 262 itp->it_value.tv_sec--; 263 } 264 } else 265 itp->it_value.tv_usec = 0; /* sec is already 0 */ 266 return (0); 267 } 268 269 /* 270 * Add and subtract routines for timevals. 271 * N.B.: subtract routine doesn't deal with 272 * results which are before the beginning, 273 * it just gets very confused in this case. 274 * Caveat emptor. 275 */ 276 timevaladd(t1, t2) 277 struct timeval *t1, *t2; 278 { 279 280 t1->tv_sec += t2->tv_sec; 281 t1->tv_usec += t2->tv_usec; 282 timevalfix(t1); 283 } 284 285 timevalsub(t1, t2) 286 struct timeval *t1, *t2; 287 { 288 289 t1->tv_sec -= t2->tv_sec; 290 t1->tv_usec -= t2->tv_usec; 291 timevalfix(t1); 292 } 293 294 timevalfix(t1) 295 struct timeval *t1; 296 { 297 298 if (t1->tv_usec < 0) { 299 t1->tv_sec--; 300 t1->tv_usec += 1000000; 301 } 302 if (t1->tv_usec >= 1000000) { 303 t1->tv_sec++; 304 t1->tv_usec -= 1000000; 305 } 306 } 307 308 #ifndef NOCOMPAT 309 otime() 310 { 311 312 u.u_r.r_time = time.tv_sec; 313 } 314 315 ostime() 316 { 317 register struct a { 318 int time; 319 } *uap = (struct a *)u.u_ap; 320 struct timeval tv; 321 322 tv.tv_sec = uap->time; 323 tv.tv_usec = 0; 324 setthetime(&tv); 325 } 326 327 /* from old timeb.h */ 328 struct timeb { 329 time_t time; 330 u_short millitm; 331 short timezone; 332 short dstflag; 333 }; 334 335 oftime() 336 { 337 register struct a { 338 struct timeb *tp; 339 } *uap; 340 struct timeb tb; 341 342 uap = (struct a *)u.u_ap; 343 (void) spl7(); 344 tb.time = time.tv_sec; 345 tb.millitm = time.tv_usec / 1000; 346 (void) spl0(); 347 tb.timezone = tz.tz_minuteswest; 348 tb.dstflag = tz.tz_dsttime; 349 if (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb)) < 0) 350 u.u_error = EFAULT; 351 } 352 353 oalarm() 354 { 355 register struct a { 356 int deltat; 357 } *uap = (struct a *)u.u_ap; 358 register struct proc *p = u.u_procp; 359 int s = spl7(); 360 361 untimeout(realitexpire, (caddr_t)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, (caddr_t)p, hzto(&p->p_realtimer.it_value)); 374 splx(s); 375 } 376 #endif 377