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