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