1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)kern_time.c 7.15 (Berkeley) 3/17/91 34 * $Id: kern_time.c,v 1.3 1993/06/27 06:01:48 andrew Exp $ 35 */ 36 37 #include "param.h" 38 #include "systm.h" 39 #include "resourcevar.h" 40 #include "kernel.h" 41 #include "proc.h" 42 43 #include "machine/cpu.h" 44 45 /* 46 * Time of day and interval timer support. 47 * 48 * These routines provide the kernel entry points to get and set 49 * the time-of-day and per-process interval timers. Subroutines 50 * here provide support for adding and subtracting timeval structures 51 * and decrementing interval timers, optionally reloading the interval 52 * timers when they expire. 53 */ 54 55 /* ARGSUSED */ 56 int 57 gettimeofday(p, uap, retval) 58 struct proc *p; 59 register struct args { 60 struct timeval *tp; 61 struct timezone *tzp; 62 } *uap; 63 int *retval; 64 { 65 struct timeval atv; 66 int error = 0; 67 68 if (uap->tp) { 69 microtime(&atv); 70 if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp, 71 sizeof (atv))) 72 return (error); 73 } 74 if (uap->tzp) 75 error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, 76 sizeof (tz)); 77 return (error); 78 } 79 80 /* ARGSUSED */ 81 int 82 settimeofday(p, uap, retval) 83 struct proc *p; 84 struct args { 85 struct timeval *tv; 86 struct timezone *tzp; 87 } *uap; 88 int *retval; 89 { 90 struct timeval atv; 91 struct timezone atz; 92 int error, s; 93 94 if (error = suser(p->p_ucred, &p->p_acflag)) 95 return (error); 96 if (uap->tv) { 97 if (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 98 sizeof (struct timeval))) 99 return (error); 100 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 101 boottime.tv_sec += atv.tv_sec - time.tv_sec; 102 s = splhigh(); time = atv; splx(s); 103 resettodr(); 104 } 105 if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, 106 sizeof (atz))) == 0) 107 tz = atz; 108 return (error); 109 } 110 111 extern int tickadj; /* "standard" clock skew, us./tick */ 112 int tickdelta; /* current clock skew, us. per tick */ 113 long timedelta; /* unapplied time correction, us. */ 114 long bigadj = 1000000; /* use 10x skew above bigadj us. */ 115 116 /* ARGSUSED */ 117 int 118 adjtime(p, uap, retval) 119 struct proc *p; 120 register struct args { 121 struct timeval *delta; 122 struct timeval *olddelta; 123 } *uap; 124 int *retval; 125 { 126 struct timeval atv, oatv; 127 register long ndelta; 128 int s, error; 129 130 if (error = suser(p->p_ucred, &p->p_acflag)) 131 return (error); 132 if (error = 133 copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof (struct timeval))) 134 return (error); 135 ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 136 if (timedelta == 0) 137 if (ndelta > bigadj) 138 tickdelta = 10 * tickadj; 139 else 140 tickdelta = tickadj; 141 if (ndelta % tickdelta) 142 ndelta = ndelta / tickadj * tickadj; 143 144 s = splclock(); 145 if (uap->olddelta) { 146 oatv.tv_sec = timedelta / 1000000; 147 oatv.tv_usec = timedelta % 1000000; 148 } 149 timedelta = ndelta; 150 splx(s); 151 152 if (uap->olddelta) 153 (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta, 154 sizeof (struct timeval)); 155 return (0); 156 } 157 158 /* 159 * Get value of an interval timer. The process virtual and 160 * profiling virtual time timers are kept in the p_stats area, since 161 * they can be swapped out. These are kept internally in the 162 * way they are specified externally: in time until they expire. 163 * 164 * The real time interval timer is kept in the process table slot 165 * for the process, and its value (it_value) is kept as an 166 * absolute time rather than as a delta, so that it is easy to keep 167 * periodic real-time signals from drifting. 168 * 169 * Virtual time timers are processed in the hardclock() routine of 170 * kern_clock.c. The real time timer is processed by a timeout 171 * routine, called from the softclock() routine. Since a callout 172 * may be delayed in real time due to interrupt processing in the system, 173 * it is possible for the real time timeout routine (realitexpire, given below), 174 * to be delayed in real time past when it is supposed to occur. It 175 * does not suffice, therefore, to reload the real timer .it_value from the 176 * real time timers .it_interval. Rather, we compute the next time in 177 * absolute time the timer should go off. 178 */ 179 /* ARGSUSED */ 180 int 181 getitimer(p, uap, retval) 182 struct proc *p; 183 register struct args { 184 u_int which; 185 struct itimerval *itv; 186 } *uap; 187 int *retval; 188 { 189 struct itimerval aitv; 190 int s; 191 192 if (uap->which > ITIMER_PROF) 193 return (EINVAL); 194 s = splclock(); 195 if (uap->which == ITIMER_REAL) { 196 /* 197 * Convert from absoulte to relative time in .it_value 198 * part of real time timer. If time for real time timer 199 * has passed return 0, else return difference between 200 * current time and time for the timer to go off. 201 */ 202 aitv = p->p_realtimer; 203 if (timerisset(&aitv.it_value)) 204 if (timercmp(&aitv.it_value, &time, <)) 205 timerclear(&aitv.it_value); 206 else 207 timevalsub(&aitv.it_value, &time); 208 } else 209 aitv = p->p_stats->p_timer[uap->which]; 210 splx(s); 211 return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, 212 sizeof (struct itimerval))); 213 } 214 215 /* ARGSUSED */ 216 int 217 setitimer(p, uap, retval) 218 struct proc *p; 219 register struct args { 220 u_int which; 221 struct itimerval *itv, *oitv; 222 } *uap; 223 int *retval; 224 { 225 struct itimerval aitv; 226 register struct itimerval *itvp; 227 int s, error; 228 229 if (uap->which > ITIMER_PROF) 230 return (EINVAL); 231 itvp = uap->itv; 232 if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 233 sizeof(struct itimerval)))) 234 return (error); 235 if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval))) 236 return (error); 237 if (itvp == 0) 238 return (0); 239 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 240 return (EINVAL); 241 s = splclock(); 242 if (uap->which == ITIMER_REAL) { 243 untimeout((timeout_t)realitexpire, (caddr_t)p); 244 if (timerisset(&aitv.it_value)) { 245 timevaladd(&aitv.it_value, &time); 246 timeout((timeout_t)realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 247 } 248 p->p_realtimer = aitv; 249 } else 250 p->p_stats->p_timer[uap->which] = aitv; 251 splx(s); 252 return (0); 253 } 254 255 /* 256 * Real interval timer expired: 257 * send process whose timer expired an alarm signal. 258 * If time is not set up to reload, then just return. 259 * Else compute next time timer should go off which is > current time. 260 * This is where delay in processing this timeout causes multiple 261 * SIGALRM calls to be compressed into one. 262 */ 263 void 264 realitexpire(p) 265 register struct proc *p; 266 { 267 int s; 268 269 psignal(p, SIGALRM); 270 if (!timerisset(&p->p_realtimer.it_interval)) { 271 timerclear(&p->p_realtimer.it_value); 272 return; 273 } 274 for (;;) { 275 s = splclock(); 276 timevaladd(&p->p_realtimer.it_value, 277 &p->p_realtimer.it_interval); 278 if (timercmp(&p->p_realtimer.it_value, &time, >)) { 279 timeout((timeout_t)realitexpire, (caddr_t)p, 280 hzto(&p->p_realtimer.it_value)); 281 splx(s); 282 return; 283 } 284 splx(s); 285 } 286 } 287 288 /* 289 * Check that a proposed value to load into the .it_value or 290 * .it_interval part of an interval timer is acceptable, and 291 * fix it to have at least minimal value (i.e. if it is less 292 * than the resolution of the clock, round it up.) 293 */ 294 int 295 itimerfix(tv) 296 struct timeval *tv; 297 { 298 299 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 300 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 301 return (EINVAL); 302 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 303 tv->tv_usec = tick; 304 return (0); 305 } 306 307 /* 308 * Decrement an interval timer by a specified number 309 * of microseconds, which must be less than a second, 310 * i.e. < 1000000. If the timer expires, then reload 311 * it. In this case, carry over (usec - old value) to 312 * reducint the value reloaded into the timer so that 313 * the timer does not drift. This routine assumes 314 * that it is called in a context where the timers 315 * on which it is operating cannot change in value. 316 */ 317 int 318 itimerdecr(itp, usec) 319 register struct itimerval *itp; 320 int usec; 321 { 322 323 if (itp->it_value.tv_usec < usec) { 324 if (itp->it_value.tv_sec == 0) { 325 /* expired, and already in next interval */ 326 usec -= itp->it_value.tv_usec; 327 goto expire; 328 } 329 itp->it_value.tv_usec += 1000000; 330 itp->it_value.tv_sec--; 331 } 332 itp->it_value.tv_usec -= usec; 333 usec = 0; 334 if (timerisset(&itp->it_value)) 335 return (1); 336 /* expired, exactly at end of interval */ 337 expire: 338 if (timerisset(&itp->it_interval)) { 339 itp->it_value = itp->it_interval; 340 itp->it_value.tv_usec -= usec; 341 if (itp->it_value.tv_usec < 0) { 342 itp->it_value.tv_usec += 1000000; 343 itp->it_value.tv_sec--; 344 } 345 } else 346 itp->it_value.tv_usec = 0; /* sec is already 0 */ 347 return (0); 348 } 349 350 /* 351 * Add and subtract routines for timevals. 352 * N.B.: subtract routine doesn't deal with 353 * results which are before the beginning, 354 * it just gets very confused in this case. 355 * Caveat emptor. 356 */ 357 void 358 timevaladd(t1, t2) 359 struct timeval *t1, *t2; 360 { 361 362 t1->tv_sec += t2->tv_sec; 363 t1->tv_usec += t2->tv_usec; 364 timevalfix(t1); 365 } 366 367 void 368 timevalsub(t1, t2) 369 struct timeval *t1, *t2; 370 { 371 372 t1->tv_sec -= t2->tv_sec; 373 t1->tv_usec -= t2->tv_usec; 374 timevalfix(t1); 375 } 376 377 void 378 timevalfix(t1) 379 struct timeval *t1; 380 { 381 382 if (t1->tv_usec < 0) { 383 t1->tv_sec--; 384 t1->tv_usec += 1000000; 385 } 386 if (t1->tv_usec >= 1000000) { 387 t1->tv_sec++; 388 t1->tv_usec -= 1000000; 389 } 390 } 391