Bypass itimerfix 100000000 limit in nanosleep1 using loop through timeouts

This commit is contained in:
ache 1997-08-13 17:55:11 +00:00
parent ccbdaeb2aa
commit 17e05ba7e2

View File

@ -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 <sys/param.h>
@ -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_