diff --git a/src/cmd/ksh93/bltins/sleep.c b/src/cmd/ksh93/bltins/sleep.c index 15df5b1a7..aaf2f128b 100644 --- a/src/cmd/ksh93/bltins/sleep.c +++ b/src/cmd/ksh93/bltins/sleep.c @@ -139,7 +139,7 @@ void sh_delay(double t, int sflag) ts.tv_sec = n; ts.tv_nsec = 1000000000 * (t - (double)n); - while(tvsleep(&ts, &tx) < 0 && errno == EINTR) + while(tvsleep(&ts, &tx) < 0) { if ((shp->trapnote & (SH_SIGSET | SH_SIGTRAP)) || sflag) return; diff --git a/src/cmd/ksh93/tests/functions.sh b/src/cmd/ksh93/tests/functions.sh index 2921f5d16..ecd0b218a 100755 --- a/src/cmd/ksh93/tests/functions.sh +++ b/src/cmd/ksh93/tests/functions.sh @@ -1126,7 +1126,7 @@ function gosleep "$bin_sleep" 1 } x=$( - (sleep .25; pid=; ps | grep sleep | read pid extra; [[ $pid ]] && kill -- "$pid") & + (sleep .25; pid=; ps 2>/dev/null | grep sleep | read pid extra; [[ $pid ]] && kill -- "$pid") & gosleep 2> /dev/null print ok ) diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 5309b04a9..136e4a173 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -40,11 +40,15 @@ if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) then err_exit RANDOM variable not working fi # SECONDS -let SECONDS=0.0 -sleep .001 -if (( SECONDS < .001 )) -then err_exit "either 'sleep' or \$SECONDS not working" +float secElapsed=0.0 secSleep=0.001 +let SECONDS=$secElapsed +sleep $secSleep +secElapsed=SECONDS +if (( secElapsed < secSleep )) +then err_exit "slept ${secElapsed} seconds instead of ${secSleep}: " \ + "either 'sleep' or \$SECONDS not working" fi +unset -v secElapsed secSleep # _ set abc def if [[ $_ != def ]] @@ -508,12 +512,11 @@ fi function foo { typeset SECONDS=0 - sleep .002 + sleep 0.002 print $SECONDS - } x=$(foo) -(( x >.001 && x < 1 )) +(( x >= 0.002 && x < 1 )) ' } 2> /dev/null || err_exit 'SECONDS not working in function' cat > $tmp/script <<-\! diff --git a/src/lib/libast/tm/tvsleep.c b/src/lib/libast/tm/tvsleep.c index 3a1b9aefe..5f65c3b52 100644 --- a/src/lib/libast/tm/tvsleep.c +++ b/src/lib/libast/tm/tvsleep.c @@ -41,6 +41,8 @@ # endif #endif +#define NANOSECONDS 1000000000L + /* * sleep for tv * non-zero exit if sleep did not complete @@ -53,11 +55,12 @@ int tvsleep(register const Tv_t* tv, register Tv_t* rv) { + int r; + #if _lib_nanosleep struct timespec stv; struct timespec srv; - int r; stv.tv_sec = tv->tv_sec; stv.tv_nsec = tv->tv_nsec; @@ -77,13 +80,11 @@ tvsleep(register const Tv_t* tv, register Tv_t* rv) #if _lib_select - struct timeval stv; + struct timeval tvSleep = { tv->tv_sec, tv->tv_nsec / 1000 }; + if (tv->tv_nsec % 1000) + ++tvSleep.tv_usec; - stv.tv_sec = tv->tv_sec; - if (!(stv.tv_usec = tv->tv_nsec / 1000)) - stv.tv_usec = 1; - if (select(0, NiL, NiL, NiL, &stv) >= 0) - return 0; + r = select(0, NiL, NiL, NiL, &tvSleep); #else @@ -162,51 +163,52 @@ tvsleep(register const Tv_t* tv, register Tv_t* rv) if (!(t = (n + 999999L) / 1000000L)) t = 1; - if (poll(&pfd, 0, t) >= 0) - return 0; + r = poll(&pfd, 0, t); #endif #endif } - bad: - if (errno == EINTR && rv) + +/* Ascertain whether we actually slept for a sufficient time. + * It is preferable to sleep a little more than necessary than too little. + */ { - tvgettime(rv); - if (rv->tv_nsec < bv.tv_nsec) + struct timespec tsAfter; + long sec, nsec; + + tvgettime(&tsAfter); + + /* Calculate seconds left to sleep */ + sec = (long)(tv->tv_sec + tv->tv_nsec / NANOSECONDS) - + ((long)tsAfter.tv_sec - (long)bv.tv_sec); + + /* Calculate nanoseconds left to sleep */ + nsec = (long)(tv->tv_nsec % NANOSECONDS) - + ((long)tsAfter.tv_nsec - (long)bv.tv_nsec); + if (nsec >= NANOSECONDS) { - rv->tv_nsec += 1000000000L; - rv->tv_sec--; + ++sec; + nsec -= NANOSECONDS; } - rv->tv_nsec -= bv.tv_nsec; - rv->tv_sec -= bv.tv_sec; - if (rv->tv_sec > tv->tv_sec) + else if (nsec < 0) { - rv->tv_sec = 0; - rv->tv_nsec = 0; + --sec; + nsec += NANOSECONDS; } - else + + if (sec >= 0 && (sec > 0 || nsec > 0)) { - rv->tv_sec = tv->tv_sec - rv->tv_sec; - if (rv->tv_nsec > tv->tv_nsec) + if (rv) { - if (!rv->tv_sec) - { - rv->tv_sec = 0; - rv->tv_nsec = 0; - } - else - { - rv->tv_sec--; - rv->tv_nsec = 1000000000L - rv->tv_nsec + tv->tv_nsec; - } + rv->tv_sec = sec; + rv->tv_nsec = nsec; } - else - rv->tv_nsec = tv->tv_nsec - rv->tv_nsec; + return -1; } } - return -1; + return r; #endif