1 /* kern_time.c 6.1 83/07/29 */ 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 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) 59 return; 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 /* 77 * Get value of an interval timer. The process virtual and 78 * profiling virtual time timers are kept in the u. area, since 79 * they can be swapped out. These are kept internally in the 80 * way they are specified externally: in time until they expire. 81 * 82 * The real time interval timer is kept in the process table slot 83 * for the process, and its value (it_value) is kept as an 84 * absolute time rather than as a delta, so that it is easy to keep 85 * periodic real-time signals from drifting. 86 * 87 * Virtual time timers are processed in the hardclock() routine of 88 * kern_clock.c. The real time timer is processed by a timeout 89 * routine, called from the softclock() routine. Since a callout 90 * may be delayed in real time due to interrupt processing in the system, 91 * it is possible for the real time timeout routine (realitexpire, given below), 92 * to be delayed in real time past when it is supposed to occur. It 93 * does not suffice, therefore, to reload the real timer .it_value from the 94 * real time timers .it_interval. Rather, we compute the next time in 95 * absolute time the timer should go off. 96 */ 97 getitimer() 98 { 99 register struct a { 100 u_int which; 101 struct itimerval *itv; 102 } *uap = (struct a *)u.u_ap; 103 struct itimerval aitv; 104 int s; 105 106 if (uap->which > 2) { 107 u.u_error = EINVAL; 108 return; 109 } 110 s = spl7(); 111 if (uap->which == ITIMER_REAL) { 112 /* 113 * Convert from absoulte to relative time in .it_value 114 * part of real time timer. If time for real time timer 115 * has passed return 0, else return difference between 116 * current time and time for the timer to go off. 117 */ 118 aitv = u.u_procp->p_realtimer; 119 if (timerisset(&aitv.it_value)) 120 if (timercmp(&aitv.it_value, &time, <)) 121 timerclear(&aitv.it_value); 122 else 123 timevalsub(&aitv.it_value, &time); 124 } else 125 aitv = u.u_timer[uap->which]; 126 splx(s); 127 u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv, 128 sizeof (struct itimerval)); 129 splx(s); 130 } 131 132 setitimer() 133 { 134 register struct a { 135 u_int which; 136 struct itimerval *itv, *oitv; 137 } *uap = (struct a *)u.u_ap; 138 struct itimerval aitv; 139 int s; 140 register struct proc *p = u.u_procp; 141 142 if (uap->which > 2) { 143 u.u_error = EINVAL; 144 return; 145 } 146 u.u_error = copyin((caddr_t)uap->itv, (caddr_t)&aitv, 147 sizeof (struct itimerval)); 148 if (u.u_error) 149 return; 150 if (uap->oitv) { 151 uap->itv = uap->oitv; 152 getitimer(); 153 } 154 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) { 155 u.u_error = EINVAL; 156 return; 157 } 158 s = spl7(); 159 if (uap->which == ITIMER_REAL) { 160 untimeout(realitexpire, (caddr_t)p); 161 if (timerisset(&aitv.it_value)) { 162 timevaladd(&aitv.it_value, &time); 163 timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 164 } 165 p->p_realtimer = aitv; 166 } else 167 u.u_timer[uap->which] = aitv; 168 splx(s); 169 } 170 171 /* 172 * Real interval timer expired: 173 * send process whose timer expired an alarm signal. 174 * If time is not set up to reload, then just return. 175 * Else compute next time timer should go off which is > current time. 176 * This is where delay in processing this timeout causes multiple 177 * SIGALRM calls to be compressed into one. 178 */ 179 realitexpire(p) 180 register struct proc *p; 181 { 182 int s; 183 184 psignal(p, SIGALRM); 185 if (!timerisset(&p->p_realtimer.it_interval)) { 186 timerclear(&p->p_realtimer.it_value); 187 return; 188 } 189 for (;;) { 190 s = spl7(); 191 timevaladd(&p->p_realtimer.it_value, 192 &p->p_realtimer.it_interval); 193 if (timercmp(&p->p_realtimer.it_value, &time, >)) { 194 timeout(realitexpire, (caddr_t)p, 195 hzto(&p->p_realtimer.it_value)); 196 splx(s); 197 return; 198 } 199 splx(s); 200 } 201 } 202 203 /* 204 * Check that a proposed value to load into the .it_value or 205 * .it_interval part of an interval timer is acceptable, and 206 * fix it to have at least minimal value (i.e. if it is less 207 * than the resolution of the clock, round it up.) 208 */ 209 itimerfix(tv) 210 struct timeval *tv; 211 { 212 213 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 214 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 215 return (EINVAL); 216 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 217 tv->tv_usec = tick; 218 return (0); 219 } 220 221 /* 222 * Decrement an interval timer by a specified number 223 * of microseconds, which must be less than a second, 224 * i.e. < 1000000. If the timer expires, then reload 225 * it. In this case, carry over (usec - old value) to 226 * reducint the value reloaded into the timer so that 227 * the timer does not drift. This routine assumes 228 * that it is called in a context where the timers 229 * on which it is operating cannot change in value. 230 */ 231 itimerdecr(itp, usec) 232 register struct itimerval *itp; 233 int usec; 234 { 235 236 if (itp->it_value.tv_usec < usec) { 237 if (itp->it_value.tv_sec == 0) { 238 /* expired, and already in next interval */ 239 usec -= itp->it_value.tv_usec; 240 goto expire; 241 } 242 itp->it_value.tv_usec += 1000000; 243 itp->it_value.tv_sec--; 244 } 245 itp->it_value.tv_usec -= usec; 246 usec = 0; 247 if (timerisset(&itp->it_value)) 248 return (1); 249 /* expired, exactly at end of interval */ 250 expire: 251 if (timerisset(&itp->it_interval)) { 252 itp->it_value = itp->it_interval; 253 itp->it_value.tv_usec -= usec; 254 if (itp->it_value.tv_usec < 0) { 255 itp->it_value.tv_usec += 1000000; 256 itp->it_value.tv_sec--; 257 } 258 } else 259 itp->it_value.tv_usec = 0; /* sec is already 0 */ 260 return (0); 261 } 262 263 /* 264 * Add and subtract routines for timevals. 265 * N.B.: subtract routine doesn't deal with 266 * results which are before the beginning, 267 * it just gets very confused in this case. 268 * Caveat emptor. 269 */ 270 timevaladd(t1, t2) 271 struct timeval *t1, *t2; 272 { 273 274 t1->tv_sec += t2->tv_sec; 275 t1->tv_usec += t2->tv_usec; 276 timevalfix(t1); 277 } 278 279 timevalsub(t1, t2) 280 struct timeval *t1, *t2; 281 { 282 283 t1->tv_sec -= t2->tv_sec; 284 t1->tv_usec -= t2->tv_usec; 285 timevalfix(t1); 286 } 287 288 timevalfix(t1) 289 struct timeval *t1; 290 { 291 292 if (t1->tv_usec < 0) { 293 t1->tv_sec--; 294 t1->tv_usec += 1000000; 295 } 296 if (t1->tv_usec >= 1000000) { 297 t1->tv_sec++; 298 t1->tv_usec -= 1000000; 299 } 300 } 301