kern_time.c revision 1.25
1/* $NetBSD: kern_time.c,v 1.25 1997/01/15 01:37:53 perry 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#include <sys/signalvar.h> 45#include <sys/syslog.h> 46 47#include <sys/mount.h> 48#include <sys/syscallargs.h> 49 50#if defined(NFSCLIENT) || defined(NFSSERVER) 51#include <nfs/rpcv2.h> 52#include <nfs/nfsproto.h> 53#include <nfs/nfs_var.h> 54#endif 55 56#include <machine/cpu.h> 57 58static void settime __P((struct timeval *)); 59 60/* 61 * Time of day and interval timer support. 62 * 63 * These routines provide the kernel entry points to get and set 64 * the time-of-day and per-process interval timers. Subroutines 65 * here provide support for adding and subtracting timeval structures 66 * and decrementing interval timers, optionally reloading the interval 67 * timers when they expire. 68 */ 69 70 71/* This function is used by clock_settime and settimeofday */ 72static void 73settime(tv) 74 struct timeval *tv; 75{ 76 struct timeval delta; 77 int s; 78 79 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 80 s = splclock(); 81 timersub(tv, &time, &delta); 82 time = *tv; 83 (void) splsoftclock(); 84 timeradd(&boottime, &delta, &boottime); 85 timeradd(&runtime, &delta, &runtime); 86# if defined(NFSCLIENT) || defined(NFSSERVER) 87 nqnfs_lease_updatetime(delta.tv_sec); 88# endif 89 splx(s); 90 resettodr(); 91} 92 93/* ARGSUSED */ 94int 95sys_clock_gettime(p, v, retval) 96 struct proc *p; 97 void *v; 98 register_t *retval; 99{ 100 register struct sys_clock_gettime_args /* { 101 syscallarg(clockid_t) clock_id; 102 syscallarg(struct timespec *) tp; 103 } */ *uap = v; 104 clockid_t clock_id; 105 struct timeval atv; 106 struct timespec ats; 107 108 clock_id = SCARG(uap, clock_id); 109 if (clock_id != CLOCK_REALTIME) 110 return (EINVAL); 111 112 microtime(&atv); 113 TIMEVAL_TO_TIMESPEC(&atv,&ats); 114 115 return copyout(&ats, SCARG(uap, tp), sizeof(ats)); 116} 117 118/* ARGSUSED */ 119int 120sys_clock_settime(p, v, retval) 121 struct proc *p; 122 void *v; 123 register_t *retval; 124{ 125 register struct sys_clock_settime_args /* { 126 syscallarg(clockid_t) clock_id; 127 syscallarg(const struct timespec *) tp; 128 } */ *uap = v; 129 clockid_t clock_id; 130 struct timeval atv; 131 struct timespec ats; 132 int error; 133 134 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 135 return (error); 136 137 clock_id = SCARG(uap, clock_id); 138 if (clock_id != CLOCK_REALTIME) 139 return (EINVAL); 140 141 if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) 142 return (error); 143 144 TIMESPEC_TO_TIMEVAL(&atv,&ats); 145 settime(&atv); 146 147 return 0; 148} 149 150int 151sys_clock_getres(p, v, retval) 152 struct proc *p; 153 void *v; 154 register_t *retval; 155{ 156 register struct sys_clock_getres_args /* { 157 syscallarg(clockid_t) clock_id; 158 syscallarg(struct timespec *) tp; 159 } */ *uap = v; 160 clockid_t clock_id; 161 struct timespec ts; 162 int error = 0; 163 164 clock_id = SCARG(uap, clock_id); 165 if (clock_id != CLOCK_REALTIME) 166 return (EINVAL); 167 168 if (SCARG(uap, tp)) { 169 ts.tv_sec = 0; 170 ts.tv_nsec = 1000000000 / hz; 171 172 error = copyout(&ts, SCARG(uap, tp), sizeof (ts)); 173 } 174 175 return error; 176} 177 178 179/* ARGSUSED */ 180int 181sys_gettimeofday(p, v, retval) 182 struct proc *p; 183 void *v; 184 register_t *retval; 185{ 186 register struct sys_gettimeofday_args /* { 187 syscallarg(struct timeval *) tp; 188 syscallarg(struct timezone *) tzp; 189 } */ *uap = v; 190 struct timeval atv; 191 int error = 0; 192 struct timezone tzfake; 193 194 if (SCARG(uap, tp)) { 195 microtime(&atv); 196 error = copyout(&atv, SCARG(uap, tp), sizeof (atv)); 197 if (error) 198 return (error); 199 } 200 if (SCARG(uap, tzp)) { 201 /* 202 * NetBSD has no kernel notion of timezone, so we just 203 * fake up a timezone struct and return it if demanded. 204 */ 205 tzfake.tz_minuteswest = 0; 206 tzfake.tz_dsttime = 0; 207 error = copyout(&tzfake, SCARG(uap, tzp), sizeof (tzfake)); 208 } 209 return (error); 210} 211 212/* ARGSUSED */ 213int 214sys_settimeofday(p, v, retval) 215 struct proc *p; 216 void *v; 217 register_t *retval; 218{ 219 struct sys_settimeofday_args /* { 220 syscallarg(const struct timeval *) tv; 221 syscallarg(const struct timezone *) tzp; 222 } */ *uap = v; 223 struct timeval atv; 224 struct timezone atz; 225 int error; 226 227 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 228 return (error); 229 /* Verify all parameters before changing time. */ 230 if (SCARG(uap, tv) && (error = copyin(SCARG(uap, tv), 231 &atv, sizeof(atv)))) 232 return (error); 233 /* XXX since we don't use tz, probably no point in doing copyin. */ 234 if (SCARG(uap, tzp) && (error = copyin(SCARG(uap, tzp), 235 &atz, sizeof(atz)))) 236 return (error); 237 if (SCARG(uap, tv)) 238 settime(&atv); 239 /* 240 * NetBSD has no kernel notion of timezone, and only an 241 * obsolete program would try to set it, so we log a warning. 242 */ 243 if (SCARG(uap, tzp)) 244 log(LOG_WARNING, "pid %d attempted to set the " 245 "(obsolete) kernel timezone.", p->p_pid); 246 return (0); 247} 248 249int tickdelta; /* current clock skew, us. per tick */ 250long timedelta; /* unapplied time correction, us. */ 251long bigadj = 1000000; /* use 10x skew above bigadj us. */ 252 253/* ARGSUSED */ 254int 255sys_adjtime(p, v, retval) 256 struct proc *p; 257 void *v; 258 register_t *retval; 259{ 260 register struct sys_adjtime_args /* { 261 syscallarg(const struct timeval *) delta; 262 syscallarg(struct timeval *) olddelta; 263 } */ *uap = v; 264 struct timeval atv; 265 register long ndelta, ntickdelta, odelta; 266 int s, error; 267 268 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 269 return (error); 270 271 error = copyin(SCARG(uap, delta), &atv, sizeof(struct timeval)); 272 if (error) 273 return (error); 274 275 /* 276 * Compute the total correction and the rate at which to apply it. 277 * Round the adjustment down to a whole multiple of the per-tick 278 * delta, so that after some number of incremental changes in 279 * hardclock(), tickdelta will become zero, lest the correction 280 * overshoot and start taking us away from the desired final time. 281 */ 282 ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 283 if (ndelta > bigadj) 284 ntickdelta = 10 * tickadj; 285 else 286 ntickdelta = tickadj; 287 if (ndelta % ntickdelta) 288 ndelta = ndelta / ntickdelta * ntickdelta; 289 290 /* 291 * To make hardclock()'s job easier, make the per-tick delta negative 292 * if we want time to run slower; then hardclock can simply compute 293 * tick + tickdelta, and subtract tickdelta from timedelta. 294 */ 295 if (ndelta < 0) 296 ntickdelta = -ntickdelta; 297 s = splclock(); 298 odelta = timedelta; 299 timedelta = ndelta; 300 tickdelta = ntickdelta; 301 splx(s); 302 303 if (SCARG(uap, olddelta)) { 304 atv.tv_sec = odelta / 1000000; 305 atv.tv_usec = odelta % 1000000; 306 (void) copyout(&atv, SCARG(uap, olddelta), 307 sizeof(struct timeval)); 308 } 309 return (0); 310} 311 312/* 313 * Get value of an interval timer. The process virtual and 314 * profiling virtual time timers are kept in the p_stats area, since 315 * they can be swapped out. These are kept internally in the 316 * way they are specified externally: in time until they expire. 317 * 318 * The real time interval timer is kept in the process table slot 319 * for the process, and its value (it_value) is kept as an 320 * absolute time rather than as a delta, so that it is easy to keep 321 * periodic real-time signals from drifting. 322 * 323 * Virtual time timers are processed in the hardclock() routine of 324 * kern_clock.c. The real time timer is processed by a timeout 325 * routine, called from the softclock() routine. Since a callout 326 * may be delayed in real time due to interrupt processing in the system, 327 * it is possible for the real time timeout routine (realitexpire, given below), 328 * to be delayed in real time past when it is supposed to occur. It 329 * does not suffice, therefore, to reload the real timer .it_value from the 330 * real time timers .it_interval. Rather, we compute the next time in 331 * absolute time the timer should go off. 332 */ 333/* ARGSUSED */ 334int 335sys_getitimer(p, v, retval) 336 struct proc *p; 337 void *v; 338 register_t *retval; 339{ 340 register struct sys_getitimer_args /* { 341 syscallarg(u_int) which; 342 syscallarg(struct itimerval *) itv; 343 } */ *uap = v; 344 struct itimerval aitv; 345 int s; 346 347 if (SCARG(uap, which) > ITIMER_PROF) 348 return (EINVAL); 349 s = splclock(); 350 if (SCARG(uap, which) == ITIMER_REAL) { 351 /* 352 * Convert from absolute to relative time in .it_value 353 * part of real time timer. If time for real time timer 354 * has passed return 0, else return difference between 355 * current time and time for the timer to go off. 356 */ 357 aitv = p->p_realtimer; 358 if (timerisset(&aitv.it_value)) 359 if (timercmp(&aitv.it_value, &time, <)) 360 timerclear(&aitv.it_value); 361 else 362 timersub(&aitv.it_value, &time, &aitv.it_value); 363 } else 364 aitv = p->p_stats->p_timer[SCARG(uap, which)]; 365 splx(s); 366 return (copyout(&aitv, SCARG(uap, itv), sizeof (struct itimerval))); 367} 368 369/* ARGSUSED */ 370int 371sys_setitimer(p, v, retval) 372 struct proc *p; 373 register void *v; 374 register_t *retval; 375{ 376 register struct sys_setitimer_args /* { 377 syscallarg(u_int) which; 378 syscallarg(const struct itimerval *) itv; 379 syscallarg(struct itimerval *) oitv; 380 } */ *uap = v; 381 struct sys_getitimer_args getargs; 382 struct itimerval aitv; 383 register const struct itimerval *itvp; 384 int s, error; 385 386 if (SCARG(uap, which) > ITIMER_PROF) 387 return (EINVAL); 388 itvp = SCARG(uap, itv); 389 if (itvp && (error = copyin(itvp, &aitv, sizeof(struct itimerval)))) 390 return (error); 391 if (SCARG(uap, oitv) != NULL) { 392 SCARG(&getargs, which) = SCARG(uap, which); 393 SCARG(&getargs, itv) = SCARG(uap, oitv); 394 if ((error = sys_getitimer(p, &getargs, retval)) != 0) 395 return (error); 396 } 397 if (itvp == 0) 398 return (0); 399 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 400 return (EINVAL); 401 s = splclock(); 402 if (SCARG(uap, which) == ITIMER_REAL) { 403 untimeout(realitexpire, p); 404 if (timerisset(&aitv.it_value)) { 405 timeradd(&aitv.it_value, &time, &aitv.it_value); 406 timeout(realitexpire, p, hzto(&aitv.it_value)); 407 } 408 p->p_realtimer = aitv; 409 } else 410 p->p_stats->p_timer[SCARG(uap, which)] = aitv; 411 splx(s); 412 return (0); 413} 414 415/* 416 * Real interval timer expired: 417 * send process whose timer expired an alarm signal. 418 * If time is not set up to reload, then just return. 419 * Else compute next time timer should go off which is > current time. 420 * This is where delay in processing this timeout causes multiple 421 * SIGALRM calls to be compressed into one. 422 */ 423void 424realitexpire(arg) 425 void *arg; 426{ 427 register struct proc *p; 428 int s; 429 430 p = (struct proc *)arg; 431 psignal(p, SIGALRM); 432 if (!timerisset(&p->p_realtimer.it_interval)) { 433 timerclear(&p->p_realtimer.it_value); 434 return; 435 } 436 for (;;) { 437 s = splclock(); 438 timeradd(&p->p_realtimer.it_value, 439 &p->p_realtimer.it_interval, &p->p_realtimer.it_value); 440 if (timercmp(&p->p_realtimer.it_value, &time, >)) { 441 timeout(realitexpire, p, 442 hzto(&p->p_realtimer.it_value)); 443 splx(s); 444 return; 445 } 446 splx(s); 447 } 448} 449 450/* 451 * Check that a proposed value to load into the .it_value or 452 * .it_interval part of an interval timer is acceptable, and 453 * fix it to have at least minimal value (i.e. if it is less 454 * than the resolution of the clock, round it up.) 455 */ 456int 457itimerfix(tv) 458 struct timeval *tv; 459{ 460 461 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 462 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 463 return (EINVAL); 464 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 465 tv->tv_usec = tick; 466 return (0); 467} 468 469/* 470 * Decrement an interval timer by a specified number 471 * of microseconds, which must be less than a second, 472 * i.e. < 1000000. If the timer expires, then reload 473 * it. In this case, carry over (usec - old value) to 474 * reduce the value reloaded into the timer so that 475 * the timer does not drift. This routine assumes 476 * that it is called in a context where the timers 477 * on which it is operating cannot change in value. 478 */ 479int 480itimerdecr(itp, usec) 481 register struct itimerval *itp; 482 int usec; 483{ 484 485 if (itp->it_value.tv_usec < usec) { 486 if (itp->it_value.tv_sec == 0) { 487 /* expired, and already in next interval */ 488 usec -= itp->it_value.tv_usec; 489 goto expire; 490 } 491 itp->it_value.tv_usec += 1000000; 492 itp->it_value.tv_sec--; 493 } 494 itp->it_value.tv_usec -= usec; 495 usec = 0; 496 if (timerisset(&itp->it_value)) 497 return (1); 498 /* expired, exactly at end of interval */ 499expire: 500 if (timerisset(&itp->it_interval)) { 501 itp->it_value = itp->it_interval; 502 itp->it_value.tv_usec -= usec; 503 if (itp->it_value.tv_usec < 0) { 504 itp->it_value.tv_usec += 1000000; 505 itp->it_value.tv_sec--; 506 } 507 } else 508 itp->it_value.tv_usec = 0; /* sec is already 0 */ 509 return (0); 510} 511