mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
sleep: guarantee sleeping specified time at minimum (#174)
With this patch, the Korn shell can now guarantee that calls to sleep on systems using the select or poll method always result in the system clock advancing by that much time, assuming no interruptions. This compensates for deficiencies in certain systems, including SCO UnixWare. Discussion: https://github.com/ksh93/ksh/pull/174 src/lib/libast/tm/tvsleep.c: - Ensure that at least the time requested to sleep has elapsed for the select and poll methods. - Simplify the logic of calculating the time remaining to sleep and handle the case of an argument of greater than 10e9 nanoseconds being passed to tvsleep. src/cmd/ksh93/bltins/sleep.c: - Eliminate the check for EINTR to handle other cases wherein we have not slept enough. src/cmd/ksh93/tests/variables.sh: - Improve the diagnostic message when the sleep test fails. - Revise the SECONDS function test to expect that we always sleep for at least the time specified. src/cmd/ksh93/tests/functions.h: - Redirect ps stderr to /dev/null. UnixWare ps prints an error message about not being able to find the controlling terminal when shtests output is piped, but we are only using ps to find the PID.
This commit is contained in:
parent
0e9aaf1635
commit
e2d54b7169
4 changed files with 50 additions and 45 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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 <<-\!
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
else
|
||||
rv->tv_nsec = tv->tv_nsec - rv->tv_nsec;
|
||||
}
|
||||
rv->tv_sec = sec;
|
||||
rv->tv_nsec = nsec;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue