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