Skip to content

Commit

Permalink
bpo-21302: Add clock_nanosleep() implementation for time.sleep() (pyt…
Browse files Browse the repository at this point in the history
…honGH-28111)

In Unix operating systems, time.sleep() now uses the clock_nanosleep() function,
if available, which allows to sleep for an interval specified with nanosecond precision.

Co-authored-by: Victor Stinner <vstinner@python.org>
  • Loading branch information
Livius90 and vstinner authored Sep 13, 2021
1 parent 3e19409 commit 85a4748
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
In Unix operating systems, :func:`time.sleep` now uses the ``clock_nanosleep()`` function,
if available, which allows to sleep for an interval specified with nanosecond precision.
36 changes: 31 additions & 5 deletions Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2053,8 +2053,13 @@ pysleep(_PyTime_t secs)
{
_PyTime_t deadline, monotonic;
#ifndef MS_WINDOWS
#ifdef HAVE_CLOCK_NANOSLEEP
struct timespec timeout_abs;
#else
struct timeval timeout;
#endif
int err = 0;
int ret = 0;
#else
_PyTime_t millisecs;
unsigned long ul_millis;
Expand All @@ -2066,20 +2071,38 @@ pysleep(_PyTime_t secs)
return -1;
}
deadline = monotonic + secs;
#if defined(HAVE_CLOCK_NANOSLEEP) && !defined(MS_WINDOWS)
if (_PyTime_AsTimespec(deadline, &timeout_abs) < 0) {
return -1;
}
#endif

do {
#ifndef MS_WINDOWS
if (_PyTime_AsTimeval(secs, &timeout, _PyTime_ROUND_CEILING) < 0)
#ifndef HAVE_CLOCK_NANOSLEEP
if (_PyTime_AsTimeval(secs, &timeout, _PyTime_ROUND_CEILING) < 0) {
return -1;
}
#endif

#ifdef HAVE_CLOCK_NANOSLEEP
Py_BEGIN_ALLOW_THREADS
err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &timeout_abs, NULL);
Py_END_ALLOW_THREADS
err = ret;
#else
Py_BEGIN_ALLOW_THREADS
ret = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
Py_END_ALLOW_THREADS
err = errno;
#endif

if (err == 0)
if (ret == 0) {
break;
}

if (errno != EINTR) {
if (err != EINTR) {
errno = err;
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
Expand Down Expand Up @@ -2114,9 +2137,11 @@ pysleep(_PyTime_t secs)
#endif

/* sleep was interrupted by SIGINT */
if (PyErr_CheckSignals())
if (PyErr_CheckSignals()) {
return -1;
}

#ifndef HAVE_CLOCK_NANOSLEEP
if (get_monotonic(&monotonic) < 0) {
return -1;
}
Expand All @@ -2125,6 +2150,7 @@ pysleep(_PyTime_t secs)
break;
}
/* retry with the recomputed delay */
#endif
} while (1);

return 0;
Expand Down
58 changes: 58 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -13252,6 +13252,64 @@ fi
done


for ac_func in clock_nanosleep
do :
ac_fn_c_check_func "$LINENO" "clock_nanosleep" "ac_cv_func_clock_nanosleep"
if test "x$ac_cv_func_clock_nanosleep" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_CLOCK_NANOSLEEP 1
_ACEOF

else

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_nanosleep in -lrt" >&5
$as_echo_n "checking for clock_nanosleep in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_nanosleep+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */

/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char clock_nanosleep ();
int
main ()
{
return clock_nanosleep ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_rt_clock_nanosleep=yes
else
ac_cv_lib_rt_clock_nanosleep=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_nanosleep" >&5
$as_echo "$ac_cv_lib_rt_clock_nanosleep" >&6; }
if test "x$ac_cv_lib_rt_clock_nanosleep" = xyes; then :

$as_echo "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h


fi


fi
done


for ac_func in clock_getres
do :
ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres"
Expand Down
6 changes: 6 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4115,6 +4115,12 @@ AC_CHECK_FUNCS(clock_settime, [], [
])
])

AC_CHECK_FUNCS(clock_nanosleep, [], [
AC_CHECK_LIB(rt, clock_nanosleep, [
AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1)
])
])

AC_MSG_CHECKING(for major, minor, and makedev)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if defined(MAJOR_IN_MKDEV)
Expand Down
3 changes: 3 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@
/* Define to 1 if you have the `clock' function. */
#undef HAVE_CLOCK

/* Define to 1 if you have the `clock_nanosleep' function. */
#undef HAVE_CLOCK_NANOSLEEP

/* Define to 1 if you have the `clock_getres' function. */
#undef HAVE_CLOCK_GETRES

Expand Down

0 comments on commit 85a4748

Please sign in to comment.