summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-10-01 09:55:28 +0200
committerGitHub <noreply@github.com>2021-10-01 09:55:28 +0200
commit1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc (patch)
treee94381603c5b5f84731ace512dbc7fbf6bc01fc7
parent3e1c5d989a884cfbeb427b6fc86012b03cb95f62 (diff)
downloadcpython-git-1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc.tar.gz
bpo-41710: PyThread_acquire_lock_timed() uses sem_clockwait() (GH-28662)
On Unix, if the sem_clockwait() function is available in the C library (glibc 2.30 and newer), the threading.Lock.acquire() method now uses the monotonic clock (time.CLOCK_MONOTONIC) for the timeout, rather than using the system clock (time.CLOCK_REALTIME), to not be affected by system clock changes. configure now checks if the sem_clockwait() function is available.
-rw-r--r--Doc/whatsnew/3.11.rst10
-rw-r--r--Misc/NEWS.d/next/Library/2021-09-30-23-00-18.bpo-41710.svuloZ.rst5
-rw-r--r--Python/thread_pthread.h39
-rwxr-xr-xconfigure167
-rw-r--r--configure.ac2
-rw-r--r--pyconfig.h.in9
6 files changed, 160 insertions, 72 deletions
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index d01d2e2631..ff376d231b 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -239,6 +239,16 @@ sqlite3
(Contributed by Aviv Palivoda, Daniel Shahaf, and Erlend E. Aasland in
:issue:`16379`.)
+threading
+---------
+
+* On Unix, if the ``sem_clockwait()`` function is available in the C library
+ (glibc 2.30 and newer), the :meth:`threading.Lock.acquire` method now uses
+ the monotonic clock (:data:`time.CLOCK_MONOTONIC`) for the timeout, rather
+ than using the system clock (:data:`time.CLOCK_REALTIME`), to not be affected
+ by system clock changes.
+ (Contributed by Livius and Victor Stinner in :issue:`41710`.)
+
time
----
diff --git a/Misc/NEWS.d/next/Library/2021-09-30-23-00-18.bpo-41710.svuloZ.rst b/Misc/NEWS.d/next/Library/2021-09-30-23-00-18.bpo-41710.svuloZ.rst
new file mode 100644
index 0000000000..d8a4f9507c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-09-30-23-00-18.bpo-41710.svuloZ.rst
@@ -0,0 +1,5 @@
+On Unix, if the ``sem_clockwait()`` function is available in the C library
+(glibc 2.30 and newer), the :meth:`threading.Lock.acquire` method now uses the
+monotonic clock (:data:`time.CLOCK_MONOTONIC`) for the timeout, rather than
+using the system clock (:data:`time.CLOCK_REALTIME`), to not be affected by
+system clock changes. Patch by Victor Stinner.
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index 3815ffae20..9b5e273f1a 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -92,7 +92,7 @@
* mutexes and condition variables:
*/
#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \
- defined(HAVE_SEM_TIMEDWAIT))
+ (defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT)))
# define USE_SEMAPHORES
#else
# undef USE_SEMAPHORES
@@ -461,17 +461,34 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
timeout = _PyTime_FromNanoseconds(-1);
}
+#ifdef HAVE_SEM_CLOCKWAIT
+ struct timespec abs_timeout;
+ // Local scope for deadline
+ {
+ _PyTime_t deadline = _PyTime_GetMonotonicClock() + timeout;
+ _PyTime_AsTimespec_clamp(deadline, &abs_timeout);
+ }
+#else
_PyTime_t deadline = 0;
- if (timeout > 0 && !intr_flag) {
+ if (timeout > 0
+ && !intr_flag
+ )
+ {
deadline = _PyTime_GetMonotonicClock() + timeout;
}
+#endif
while (1) {
if (timeout > 0) {
- _PyTime_t t = _PyTime_GetSystemClock() + timeout;
+#ifdef HAVE_SEM_CLOCKWAIT
+ status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
+ &abs_timeout));
+#else
+ _PyTime_t abs_timeout = _PyTime_GetSystemClock() + timeout;
struct timespec ts;
- _PyTime_AsTimespec_clamp(t, &ts);
+ _PyTime_AsTimespec_clamp(abs_timeout, &ts);
status = fix_status(sem_timedwait(thelock, &ts));
+#endif
}
else if (timeout == 0) {
status = fix_status(sem_trywait(thelock));
@@ -486,6 +503,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
break;
}
+ // sem_clockwait() uses an absolute timeout, there is no need
+ // to recompute the relative timeout.
+#ifndef HAVE_SEM_CLOCKWAIT
if (timeout > 0) {
/* wait interrupted by a signal (EINTR): recompute the timeout */
_PyTime_t timeout = deadline - _PyTime_GetMonotonicClock();
@@ -494,17 +514,24 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
break;
}
}
+#endif
}
/* Don't check the status if we're stopping because of an interrupt. */
if (!(intr_flag && status == EINTR)) {
if (timeout > 0) {
- if (status != ETIMEDOUT)
+ if (status != ETIMEDOUT) {
+#ifdef HAVE_SEM_CLOCKWAIT
+ CHECK_STATUS("sem_clockwait");
+#else
CHECK_STATUS("sem_timedwait");
+#endif
+ }
}
else if (timeout == 0) {
- if (status != EAGAIN)
+ if (status != EAGAIN) {
CHECK_STATUS("sem_trywait");
+ }
}
else {
CHECK_STATUS("sem_wait");
diff --git a/configure b/configure
index 4acf91f221..75e2e296f1 100755
--- a/configure
+++ b/configure
@@ -9764,7 +9764,7 @@ then
BLDSHARED="$LDSHARED"
fi
;;
- Linux*|GNU*|QNX*|VxWorks*)
+ Linux*|GNU*|QNX*|VxWorks*|Haiku*)
LDSHARED='$(CC) -shared'
LDCXXSHARED='$(CXX) -shared';;
FreeBSD*)
@@ -9835,6 +9835,7 @@ then
Linux-android*) ;;
Linux*|GNU*) CCSHARED="-fPIC";;
FreeBSD*|NetBSD*|OpenBSD*|DragonFly*) CCSHARED="-fPIC";;
+ Haiku*) CCSHARED="-fPIC";;
OpenUNIX*|UnixWare*)
if test "$GCC" = "yes"
then CCSHARED="-fPIC"
@@ -10562,6 +10563,48 @@ if test "x$ac_cv_lib_socket_socket" = xyes; then :
fi
# SVR4 sockets
+# Haiku system library
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5
+$as_echo_n "checking for socket in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_socket+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork $LIBS $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 socket ();
+int
+main ()
+{
+return socket ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_network_socket=yes
+else
+ ac_cv_lib_network_socket=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_network_socket" >&5
+$as_echo "$ac_cv_lib_network_socket" >&6; }
+if test "x$ac_cv_lib_network_socket" = xyes; then :
+ LIBS="-lnetwork $LIBS"
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-libs" >&5
$as_echo_n "checking for --with-libs... " >&6; }
@@ -11774,7 +11817,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
pthread_condattr_setclock pthread_init pthread_kill pwrite pwritev pwritev2 \
readlink readlinkat readv realpath renameat \
- sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
+ sem_open sem_timedwait sem_clockwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
@@ -13252,19 +13295,19 @@ fi
done
-for ac_func in clock_nanosleep
+for ac_func in clock_getres
do :
- ac_fn_c_check_func "$LINENO" "clock_nanosleep" "ac_cv_func_clock_nanosleep"
-if test "x$ac_cv_func_clock_nanosleep" = xyes; then :
+ ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres"
+if test "x$ac_cv_func_clock_getres" = xyes; then :
cat >>confdefs.h <<_ACEOF
-#define HAVE_CLOCK_NANOSLEEP 1
+#define HAVE_CLOCK_GETRES 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 "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5
+$as_echo_n "checking for clock_getres in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_getres+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -13278,29 +13321,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char clock_nanosleep ();
+char clock_getres ();
int
main ()
{
-return clock_nanosleep ();
+return clock_getres ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_rt_clock_nanosleep=yes
+ ac_cv_lib_rt_clock_getres=yes
else
- ac_cv_lib_rt_clock_nanosleep=no
+ ac_cv_lib_rt_clock_getres=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 "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_getres" >&5
+$as_echo "$ac_cv_lib_rt_clock_getres" >&6; }
+if test "x$ac_cv_lib_rt_clock_getres" = xyes; then :
- $as_echo "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h
+ $as_echo "#define HAVE_CLOCK_GETRES 1" >>confdefs.h
fi
@@ -13310,19 +13353,19 @@ fi
done
-for ac_func in nanosleep
+for ac_func in clock_settime
do :
- ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
-if test "x$ac_cv_func_nanosleep" = xyes; then :
+ ac_fn_c_check_func "$LINENO" "clock_settime" "ac_cv_func_clock_settime"
+if test "x$ac_cv_func_clock_settime" = xyes; then :
cat >>confdefs.h <<_ACEOF
-#define HAVE_NANOSLEEP 1
+#define HAVE_CLOCK_SETTIME 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 "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5
+$as_echo_n "checking for clock_settime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_settime+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -13336,29 +13379,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char nanosleep ();
+char clock_settime ();
int
main ()
{
-return nanosleep ();
+return clock_settime ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_rt_nanosleep=yes
+ ac_cv_lib_rt_clock_settime=yes
else
- ac_cv_lib_rt_nanosleep=no
+ ac_cv_lib_rt_clock_settime=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 "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_settime" >&5
+$as_echo "$ac_cv_lib_rt_clock_settime" >&6; }
+if test "x$ac_cv_lib_rt_clock_settime" = xyes; then :
- $as_echo "#define HAVE_NANOSLEEP 1" >>confdefs.h
+ $as_echo "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h
fi
@@ -13368,19 +13411,19 @@ fi
done
-for ac_func in clock_getres
+for ac_func in clock_nanosleep
do :
- ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres"
-if test "x$ac_cv_func_clock_getres" = xyes; then :
+ 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_GETRES 1
+#define HAVE_CLOCK_NANOSLEEP 1
_ACEOF
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5
-$as_echo_n "checking for clock_getres in -lrt... " >&6; }
-if ${ac_cv_lib_rt_clock_getres+:} false; then :
+ { $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
@@ -13394,29 +13437,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char clock_getres ();
+char clock_nanosleep ();
int
main ()
{
-return clock_getres ();
+return clock_nanosleep ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_rt_clock_getres=yes
+ ac_cv_lib_rt_clock_nanosleep=yes
else
- ac_cv_lib_rt_clock_getres=no
+ 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_getres" >&5
-$as_echo "$ac_cv_lib_rt_clock_getres" >&6; }
-if test "x$ac_cv_lib_rt_clock_getres" = xyes; then :
+{ $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_GETRES 1" >>confdefs.h
+ $as_echo "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h
fi
@@ -13426,19 +13469,19 @@ fi
done
-for ac_func in clock_settime
+for ac_func in nanosleep
do :
- ac_fn_c_check_func "$LINENO" "clock_settime" "ac_cv_func_clock_settime"
-if test "x$ac_cv_func_clock_settime" = xyes; then :
+ 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_CLOCK_SETTIME 1
+#define HAVE_NANOSLEEP 1
_ACEOF
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5
-$as_echo_n "checking for clock_settime in -lrt... " >&6; }
-if ${ac_cv_lib_rt_clock_settime+:} false; then :
+ { $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
@@ -13452,29 +13495,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char clock_settime ();
+char nanosleep ();
int
main ()
{
-return clock_settime ();
+return nanosleep ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_rt_clock_settime=yes
+ ac_cv_lib_rt_nanosleep=yes
else
- ac_cv_lib_rt_clock_settime=no
+ 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_clock_settime" >&5
-$as_echo "$ac_cv_lib_rt_clock_settime" >&6; }
-if test "x$ac_cv_lib_rt_clock_settime" = xyes; then :
+{ $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_CLOCK_SETTIME 1" >>confdefs.h
+ $as_echo "#define HAVE_NANOSLEEP 1" >>confdefs.h
fi
diff --git a/configure.ac b/configure.ac
index 48d86ef791..908dd28e7a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3744,7 +3744,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
pthread_condattr_setclock pthread_init pthread_kill pwrite pwritev pwritev2 \
readlink readlinkat readv realpath renameat \
- sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
+ sem_open sem_timedwait sem_clockwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid sethostname \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 23d7111b9f..862c083604 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -136,15 +136,15 @@
/* 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
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
+/* Define to 1 if you have the `clock_nanosleep' function. */
+#undef HAVE_CLOCK_NANOSLEEP
+
/* Define to 1 if you have the `clock_settime' function. */
#undef HAVE_CLOCK_SETTIME
@@ -908,6 +908,9 @@
/* Define to 1 if you have the `sched_setscheduler' function. */
#undef HAVE_SCHED_SETSCHEDULER
+/* Define to 1 if you have the `sem_clockwait' function. */
+#undef HAVE_SEM_CLOCKWAIT
+
/* Define to 1 if you have the `sem_getvalue' function. */
#undef HAVE_SEM_GETVALUE