summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>1997-08-13 17:55:11 +0000
committerache <ache@FreeBSD.org>1997-08-13 17:55:11 +0000
commit17e05ba7e22711bea49b3d84e522c1355d55900c (patch)
tree822642972d5a96a6762c7ebfb5cbbeb8c61c2cf8
parentccbdaeb2aaaff8d6b64f923ffc746cd639d4ada9 (diff)
downloadFreeBSD-src-17e05ba7e22711bea49b3d84e522c1355d55900c.zip
FreeBSD-src-17e05ba7e22711bea49b3d84e522c1355d55900c.tar.gz
Bypass itimerfix 100000000 limit in nanosleep1 using loop through timeouts
-rw-r--r--sys/kern/kern_time.c110
1 files changed, 64 insertions, 46 deletions
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 2caef60..e938b5e 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 <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);
-
- 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.
+ if (itimerfix(&atv)) {
+ n = atv.tv_sec / 100000000;
+ rtv = atv;
+ rtv.tv_sec %= 100000000;
+ (void)itimerfix(&rtv);
+ } else
+ n = 0;
+
+ 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_
OpenPOWER on IntegriCloud