mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
3e1c5d989a
commit
1ee0f94d16
|
@ -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
|
||||
----
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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");
|
||||
|
|
|
@ -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,122 +13295,6 @@ 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 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"
|
||||
|
@ -13484,6 +13411,122 @@ 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 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
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for major" >&5
|
||||
$as_echo_n "checking for major... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue