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