aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-09-25 14:36:26 +0200
committerGitHub <noreply@github.com>2021-09-25 14:36:26 +0200
commit7834ff26cbcd4d8394d64d80d9f51a364d38b1c6 (patch)
treee7c785c78db85d08be01a0f081589ea6d1a48614
parentbpo-43914: Whats New 310: add new SyntaxError attributes (GH-28558) (diff)
downloadcpython-7834ff26cbcd4d8394d64d80d9f51a364d38b1c6.tar.gz
cpython-7834ff26cbcd4d8394d64d80d9f51a364d38b1c6.tar.bz2
cpython-7834ff26cbcd4d8394d64d80d9f51a364d38b1c6.zip
bpo-21302: Add nanosleep() implementation for time.sleep() in Unix (GH-28545)
Co-authored-by: Livius <egyszeregy@freemail.hu>
-rw-r--r--Doc/library/time.rst16
-rw-r--r--Doc/whatsnew/3.11.rst7
-rw-r--r--Misc/NEWS.d/next/Library/2021-09-22-23-56-15.bpo-21302.vvQ3Su.rst1
-rw-r--r--Modules/timemodule.c56
-rwxr-xr-xconfigure58
-rw-r--r--configure.ac6
-rw-r--r--pyconfig.h.in3
7 files changed, 114 insertions, 33 deletions
diff --git a/Doc/library/time.rst b/Doc/library/time.rst
index d91862cc38b..69e5274f1ce 100644
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -364,16 +364,18 @@ Functions
threads ready to run, the function returns immediately, and the thread
continues execution.
- Implementation:
+ Unix implementation:
- * On Unix, ``clock_nanosleep()`` is used if available (resolution: 1 ns),
- or ``select()`` is used otherwise (resolution: 1 us).
- * On Windows, a waitable timer is used (resolution: 100 ns). If *secs* is
- zero, ``Sleep(0)`` is used.
+ * Use ``clock_nanosleep()`` if available (resolution: 1 ns);
+ * Or use ``nanosleep()`` if available (resolution: 1 ns);
+ * Or use ``select()`` (resolution: 1 us).
+
+ On Windows, a waitable timer is used (resolution: 100 ns). If *secs* is
+ zero, ``Sleep(0)`` is used.
.. versionchanged:: 3.11
- On Unix, the ``clock_nanosleep()`` function is now used if available.
- On Windows, a waitable timer is now used.
+ On Unix, the ``clock_nanosleep()`` and ``nanosleep()`` functions are now
+ used if available. On Windows, a waitable timer is now used.
.. versionchanged:: 3.5
The function now sleeps at least *secs* even if the sleep is interrupted
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 0e56b462f12..818208edbf2 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -242,9 +242,10 @@ sqlite3
time
----
-* On Unix, :func:`time.sleep` now uses the ``clock_nanosleep()`` function, if
- available, which has a resolution of 1 ns (10^-6 sec), rather than using
- ``select()`` which has a resolution of 1 us (10^-9 sec).
+* On Unix, :func:`time.sleep` now uses the ``clock_nanosleep()`` or
+ ``nanosleep()`` function, if available, which has a resolution of 1 ns (10^-6
+ sec), rather than using ``select()`` which has a resolution of 1 us (10^-9
+ sec).
(Contributed by Livius and Victor Stinner in :issue:`21302`.)
* On Windows, :func:`time.sleep` now uses a waitable timer which has a
diff --git a/Misc/NEWS.d/next/Library/2021-09-22-23-56-15.bpo-21302.vvQ3Su.rst b/Misc/NEWS.d/next/Library/2021-09-22-23-56-15.bpo-21302.vvQ3Su.rst
new file mode 100644
index 00000000000..52ee8d7cc64
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-09-22-23-56-15.bpo-21302.vvQ3Su.rst
@@ -0,0 +1 @@
+In Unix operating systems, :func:`time.sleep` now uses the ``nanosleep()`` function, if ``clock_nanosleep()`` is not available but ``nanosleep()`` is available. ``nanosleep()`` allows to sleep with nanosecond precision. \ No newline at end of file
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 53ec86eb398..4639afa590a 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -63,7 +63,7 @@
#define SEC_TO_NS (1000 * 1000 * 1000)
/* Forward declarations */
-static int pysleep(_PyTime_t);
+static int pysleep(_PyTime_t timeout);
static PyObject*
@@ -357,17 +357,17 @@ Return the clk_id of a thread's CPU time clock.");
#endif /* HAVE_PTHREAD_GETCPUCLOCKID */
static PyObject *
-time_sleep(PyObject *self, PyObject *obj)
+time_sleep(PyObject *self, PyObject *timeout_obj)
{
- _PyTime_t secs;
- if (_PyTime_FromSecondsObject(&secs, obj, _PyTime_ROUND_TIMEOUT))
+ _PyTime_t timeout;
+ if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT))
return NULL;
- if (secs < 0) {
+ if (timeout < 0) {
PyErr_SetString(PyExc_ValueError,
"sleep length must be non-negative");
return NULL;
}
- if (pysleep(secs) != 0) {
+ if (pysleep(timeout) != 0) {
return NULL;
}
Py_RETURN_NONE;
@@ -2050,15 +2050,17 @@ PyInit_time(void)
// On error, raise an exception and return -1.
// On success, return 0.
static int
-pysleep(_PyTime_t secs)
+pysleep(_PyTime_t timeout)
{
- assert(secs >= 0);
+ assert(timeout >= 0);
#ifndef MS_WINDOWS
#ifdef HAVE_CLOCK_NANOSLEEP
struct timespec timeout_abs;
+#elif defined(HAVE_NANOSLEEP)
+ struct timespec timeout_ts;
#else
- struct timeval timeout;
+ struct timeval timeout_tv;
#endif
_PyTime_t deadline, monotonic;
int err = 0;
@@ -2066,7 +2068,7 @@ pysleep(_PyTime_t secs)
if (get_monotonic(&monotonic) < 0) {
return -1;
}
- deadline = monotonic + secs;
+ deadline = monotonic + timeout;
#ifdef HAVE_CLOCK_NANOSLEEP
if (_PyTime_AsTimespec(deadline, &timeout_abs) < 0) {
return -1;
@@ -2074,24 +2076,31 @@ pysleep(_PyTime_t secs)
#endif
do {
-#ifndef HAVE_CLOCK_NANOSLEEP
- if (_PyTime_AsTimeval(secs, &timeout, _PyTime_ROUND_CEILING) < 0) {
+#ifdef HAVE_CLOCK_NANOSLEEP
+ // use timeout_abs
+#elif defined(HAVE_NANOSLEEP)
+ if (_PyTime_AsTimespec(timeout, &timeout_ts) < 0) {
+ return -1;
+ }
+#else
+ if (_PyTime_AsTimeval(timeout, &timeout_tv, _PyTime_ROUND_CEILING) < 0) {
return -1;
}
#endif
int ret;
-#ifdef HAVE_CLOCK_NANOSLEEP
Py_BEGIN_ALLOW_THREADS
+#ifdef HAVE_CLOCK_NANOSLEEP
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &timeout_abs, NULL);
- Py_END_ALLOW_THREADS
err = ret;
+#elif defined(HAVE_NANOSLEEP)
+ ret = nanosleep(&timeout_ts, NULL);
+ err = errno;
#else
- Py_BEGIN_ALLOW_THREADS
- ret = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
- Py_END_ALLOW_THREADS
+ ret = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout_tv);
err = errno;
#endif
+ Py_END_ALLOW_THREADS
if (ret == 0) {
break;
@@ -2112,8 +2121,8 @@ pysleep(_PyTime_t secs)
if (get_monotonic(&monotonic) < 0) {
return -1;
}
- secs = deadline - monotonic;
- if (secs < 0) {
+ timeout = deadline - monotonic;
+ if (timeout < 0) {
break;
}
/* retry with the recomputed delay */
@@ -2122,10 +2131,11 @@ pysleep(_PyTime_t secs)
return 0;
#else // MS_WINDOWS
- _PyTime_t timeout = _PyTime_As100Nanoseconds(secs, _PyTime_ROUND_CEILING);
+ _PyTime_t timeout_100ns = _PyTime_As100Nanoseconds(timeout,
+ _PyTime_ROUND_CEILING);
// Maintain Windows Sleep() semantics for time.sleep(0)
- if (timeout == 0) {
+ if (timeout_100ns == 0) {
Py_BEGIN_ALLOW_THREADS
// A value of zero causes the thread to relinquish the remainder of its
// time slice to any other thread that is ready to run. If there are no
@@ -2138,9 +2148,9 @@ pysleep(_PyTime_t secs)
LARGE_INTEGER relative_timeout;
// No need to check for integer overflow, both types are signed
- assert(sizeof(relative_timeout) == sizeof(timeout));
+ assert(sizeof(relative_timeout) == sizeof(timeout_100ns));
// SetWaitableTimer(): a negative due time indicates relative time
- relative_timeout.QuadPart = -timeout;
+ relative_timeout.QuadPart = -timeout_100ns;
HANDLE timer = CreateWaitableTimerW(NULL, FALSE, NULL);
if (timer == NULL) {
diff --git a/configure b/configure
index 2e3c9ba7bad..4acf91f2210 100755
--- a/configure
+++ b/configure
@@ -13310,6 +13310,64 @@ fi
done
+for ac_func in nanosleep
+do :
+ ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
+if test "x$ac_cv_func_nanosleep" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_NANOSLEEP 1
+_ACEOF
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5
+$as_echo_n "checking for nanosleep in -lrt... " >&6; }
+if ${ac_cv_lib_rt_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 nanosleep ();
+int
+main ()
+{
+return nanosleep ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_rt_nanosleep=yes
+else
+ ac_cv_lib_rt_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_nanosleep" >&5
+$as_echo "$ac_cv_lib_rt_nanosleep" >&6; }
+if test "x$ac_cv_lib_rt_nanosleep" = xyes; then :
+
+ $as_echo "#define HAVE_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"
diff --git a/configure.ac b/configure.ac
index 4a0694c442f..48d86ef7919 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4121,6 +4121,12 @@ AC_CHECK_FUNCS(clock_nanosleep, [], [
])
])
+AC_CHECK_FUNCS(nanosleep, [], [
+ AC_CHECK_LIB(rt, nanosleep, [
+ AC_DEFINE(HAVE_NANOSLEEP, 1)
+ ])
+])
+
AC_MSG_CHECKING(for major, minor, and makedev)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if defined(MAJOR_IN_MKDEV)
diff --git a/pyconfig.h.in b/pyconfig.h.in
index d6408e9415e..23d7111b9f7 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -736,6 +736,9 @@
/* Define to 1 if you have the `mremap' function. */
#undef HAVE_MREMAP
+/* Define to 1 if you have the `nanosleep' function. */
+#undef HAVE_NANOSLEEP
+
/* Define to 1 if you have the <ncurses.h> header file. */
#undef HAVE_NCURSES_H