diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 2caef6000331..e938b5e04d10 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 - * $Id: kern_time.c,v 1.29 1997/06/24 18:20:50 jhay Exp $ + * $Id: kern_time.c,v 1.30 1997/08/03 07:26:50 bde Exp $ */ #include @@ -210,59 +210,77 @@ nanosleep1(p, rqt, rmt) struct proc *p; struct timespec *rqt, *rmt; { - struct timeval atv, utv; - int error, s, timo; + struct timeval atv, utv, rtv; + int error, s, timo, i, n; - if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) + if (rqt->tv_sec < 0 || rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); TIMESPEC_TO_TIMEVAL(&atv, rqt) - if (itimerfix(&atv)) - return (EINVAL); - /* - * XXX this is not as careful as settimeofday() about minimising - * interrupt latency. The hzto() interface is inconvenient as usual. - */ - s = splclock(); - timevaladd(&atv, &time); - timo = hzto(&atv); - splx(s); + if (itimerfix(&atv)) { + n = atv.tv_sec / 100000000; + rtv = atv; + rtv.tv_sec %= 100000000; + (void)itimerfix(&rtv); + } else + n = 0; - p->p_sleepend = &atv; - error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", timo); - p->p_sleepend = NULL; - - if (error == ERESTART) - error = EINTR; - if (error == EWOULDBLOCK) - error = 0; - if (rmt != NULL) { - /*- - * XXX this is unnecessary and possibly wrong if the timeout - * expired. Then the remaining time should be zero. If the - * calculation gives a nonzero value, then we have a bug. - * (1) if settimeofday() was called, then the calculation is - * probably wrong, since `time' has probably become - * inconsistent with the ending time `atv'. - * XXX (1) should be fixed now with p->p_sleepend; - * (2) otherwise, our calculation of `timo' was wrong, perhaps - * due to `tick' being wrong when hzto() was called or - * changing afterwards (it can be wrong or change due to - * hzto() not knowing about adjtime(2) or tickadj(8)). - * Then we should be sleeping again instead instead of - * returning. Rounding up in hzto() probably fixes this - * problem for small timeouts, but the absolute error may - * be large for large timeouts. + for (i = 0, error = EWOULDBLOCK; + i <= n && error == EWOULDBLOCK; + i++) { + if (n > 0) { + if (i == n) + atv = rtv; + else { + atv.tv_sec = 100000000; + atv.tv_usec = 0; + } + } + /* + * XXX this is not as careful as settimeofday() about minimising + * interrupt latency. The hzto() interface is inconvenient as usual. */ s = splclock(); - utv = time; + timevaladd(&atv, &time); + timo = hzto(&atv); splx(s); - timevalsub(&atv, &utv); - if (atv.tv_sec < 0) - timerclear(&atv); - TIMEVAL_TO_TIMESPEC(&atv, rmt); + + p->p_sleepend = &atv; + error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", timo); + p->p_sleepend = NULL; + + if (error == ERESTART) + error = EINTR; + if (rmt != NULL && (i == n || error != EWOULDBLOCK)) { + /*- + * XXX this is unnecessary and possibly wrong if the timeout + * expired. Then the remaining time should be zero. If the + * calculation gives a nonzero value, then we have a bug. + * (1) if settimeofday() was called, then the calculation is + * probably wrong, since `time' has probably become + * inconsistent with the ending time `atv'. + * XXX (1) should be fixed now with p->p_sleepend; + * (2) otherwise, our calculation of `timo' was wrong, perhaps + * due to `tick' being wrong when hzto() was called or + * changing afterwards (it can be wrong or change due to + * hzto() not knowing about adjtime(2) or tickadj(8)). + * Then we should be sleeping again instead instead of + * returning. Rounding up in hzto() probably fixes this + * problem for small timeouts, but the absolute error may + * be large for large timeouts. + */ + s = splclock(); + utv = time; + splx(s); + timevalsub(&atv, &utv); + if (atv.tv_sec < 0) + timerclear(&atv); + if (n > 0) + atv.tv_sec += (n - i) * 100000000; + TIMEVAL_TO_TIMESPEC(&atv, rmt); + } } - return (error); + return (error == EWOULDBLOCK ? 0 : error); } #ifndef _SYS_SYSPROTO_H_