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