1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

y2038: nptl: Convert pthread_{clock|timed}join_np to support 64 bit time

The pthread_clockjoin_np and pthread_timedjoin_np have been converted to
support 64 bit time.

This change introduces new futex_timed_wait_cancel64 function in
./sysdeps/nptl/futex-internal.h, which uses futex_time64 where possible
and tries to replace low-level preprocessor macros from
lowlevellock-futex.h
The pthread_{timed|clock}join_np only accept absolute time. Moreover,
there is no need to check for NULL passed as *abstime pointer as
clockwait_tid() always passes struct __timespec64.

For systems with __TIMESIZE != 64 && __WORDSIZE == 32:
- Conversions between 64 bit time to 32 bit are necessary
- Redirection to __pthread_{clock|timed}join_np64 will provide support
  for 64 bit time

Build tests:
./src/scripts/build-many-glibcs.py glibcs

Run-time tests:
- Run specific tests on ARM/x86 32bit systems (qemu):
  https://github.com/lmajewski/meta-y2038 and run tests:
  https://github.com/lmajewski/y2038-tests/commits/master

Above tests were performed with Y2038 redirection applied as well as without
to test the proper usage of both __pthread_{timed|clock}join_np64 and
__pthread_{timed|clock}join_np.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Lukasz Majewski
2020-07-20 15:50:12 +02:00
parent 12b2fd0ef9
commit 4a14cb87ca
5 changed files with 110 additions and 14 deletions

View File

@ -458,6 +458,20 @@ extern int __pthread_cond_init (pthread_cond_t *cond,
libc_hidden_proto (__pthread_cond_init) libc_hidden_proto (__pthread_cond_init)
extern int __pthread_cond_signal (pthread_cond_t *cond); extern int __pthread_cond_signal (pthread_cond_t *cond);
extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
#if __TIMESIZE == 64
# define __pthread_clockjoin_np64 __pthread_clockjoin_np
# define __pthread_timedjoin_np64 __pthread_timedjoin_np
#else
extern int __pthread_clockjoin_np64 (pthread_t threadid, void **thread_return,
clockid_t clockid,
const struct __timespec64 *abstime);
libc_hidden_proto (__pthread_clockjoin_np64)
extern int __pthread_timedjoin_np64 (pthread_t threadid, void **thread_return,
const struct __timespec64 *abstime);
libc_hidden_proto (__pthread_timedjoin_np64)
#endif
extern int __pthread_cond_timedwait (pthread_cond_t *cond, extern int __pthread_cond_timedwait (pthread_cond_t *cond,
pthread_mutex_t *mutex, pthread_mutex_t *mutex,
const struct timespec *abstime); const struct timespec *abstime);
@ -488,7 +502,7 @@ extern int __pthread_enable_asynccancel (void) attribute_hidden;
extern void __pthread_disable_asynccancel (int oldtype) attribute_hidden; extern void __pthread_disable_asynccancel (int oldtype) attribute_hidden;
extern void __pthread_testcancel (void); extern void __pthread_testcancel (void);
extern int __pthread_clockjoin_ex (pthread_t, void **, clockid_t, extern int __pthread_clockjoin_ex (pthread_t, void **, clockid_t,
const struct timespec *, bool) const struct __timespec64 *, bool)
attribute_hidden; attribute_hidden;
extern int __pthread_sigmask (int, const sigset_t *, sigset_t *); extern int __pthread_sigmask (int, const sigset_t *, sigset_t *);
libc_hidden_proto (__pthread_sigmask); libc_hidden_proto (__pthread_sigmask);

View File

@ -16,14 +16,27 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include <time.h>
#include "pthreadP.h" #include "pthreadP.h"
int int
__pthread_clockjoin_np (pthread_t threadid, void **thread_return, __pthread_clockjoin_np64 (pthread_t threadid, void **thread_return,
clockid_t clockid, clockid_t clockid, const struct __timespec64 *abstime)
const struct timespec *abstime)
{ {
return __pthread_clockjoin_ex (threadid, thread_return, return __pthread_clockjoin_ex (threadid, thread_return,
clockid, abstime, true); clockid, abstime, true);
} }
#if __TIMESIZE != 64
libc_hidden_def (__pthread_clockjoin_np64)
int
__pthread_clockjoin_np (pthread_t threadid, void **thread_return,
clockid_t clockid, const struct timespec *abstime)
{
struct __timespec64 ts64 = valid_timespec_to_timespec64 (*abstime);
return __pthread_clockjoin_np64 (threadid, thread_return, clockid, &ts64);
}
#endif
weak_alias (__pthread_clockjoin_np, pthread_clockjoin_np) weak_alias (__pthread_clockjoin_np, pthread_clockjoin_np)

View File

@ -20,6 +20,7 @@
#include <atomic.h> #include <atomic.h>
#include <stap-probe.h> #include <stap-probe.h>
#include <time.h> #include <time.h>
#include <futex-internal.h>
static void static void
cleanup (void *arg) cleanup (void *arg)
@ -37,9 +38,11 @@ cleanup (void *arg)
afterwards. The kernel up to version 3.16.3 does not use the private futex afterwards. The kernel up to version 3.16.3 does not use the private futex
operations for futex wake-up when the clone terminates. */ operations for futex wake-up when the clone terminates. */
static int static int
clockwait_tid (pid_t *tidp, clockid_t clockid, const struct timespec *abstime) clockwait_tid (pid_t *tidp, clockid_t clockid,
const struct __timespec64 *abstime)
{ {
pid_t tid; pid_t tid;
int ret;
if (! valid_nanoseconds (abstime->tv_nsec)) if (! valid_nanoseconds (abstime->tv_nsec))
return EINVAL; return EINVAL;
@ -47,11 +50,11 @@ clockwait_tid (pid_t *tidp, clockid_t clockid, const struct timespec *abstime)
/* Repeat until thread terminated. */ /* Repeat until thread terminated. */
while ((tid = *tidp) != 0) while ((tid = *tidp) != 0)
{ {
struct timespec rt; struct __timespec64 rt;
/* Get the current time. This can only fail if clockid is /* Get the current time. This can only fail if clockid is
invalid. */ invalid. */
if (__glibc_unlikely (__clock_gettime (clockid, &rt))) if (__glibc_unlikely (__clock_gettime64 (clockid, &rt)))
return EINVAL; return EINVAL;
/* Compute relative timeout. */ /* Compute relative timeout. */
@ -70,9 +73,9 @@ clockwait_tid (pid_t *tidp, clockid_t clockid, const struct timespec *abstime)
/* If *tidp == tid, wait until thread terminates or the wait times out. /* If *tidp == tid, wait until thread terminates or the wait times out.
The kernel up to version 3.16.3 does not use the private futex The kernel up to version 3.16.3 does not use the private futex
operations for futex wake-up when the clone terminates. */ operations for futex wake-up when the clone terminates. */
if (lll_futex_timed_wait_cancel (tidp, tid, &rt, LLL_SHARED) ret = futex_timed_wait_cancel64 (tidp, tid, &rt, LLL_SHARED);
== -ETIMEDOUT) if (ret == -ETIMEDOUT || ret == -EOVERFLOW)
return ETIMEDOUT; return -ret;
} }
return 0; return 0;
@ -80,8 +83,8 @@ clockwait_tid (pid_t *tidp, clockid_t clockid, const struct timespec *abstime)
int int
__pthread_clockjoin_ex (pthread_t threadid, void **thread_return, __pthread_clockjoin_ex (pthread_t threadid, void **thread_return,
clockid_t clockid, clockid_t clockid,
const struct timespec *abstime, bool block) const struct __timespec64 *abstime, bool block)
{ {
struct pthread *pd = (struct pthread *) threadid; struct pthread *pd = (struct pthread *) threadid;

View File

@ -16,13 +16,27 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <time.h>
#include "pthreadP.h" #include "pthreadP.h"
int int
__pthread_timedjoin_np (pthread_t threadid, void **thread_return, __pthread_timedjoin_np64 (pthread_t threadid, void **thread_return,
const struct timespec *abstime) const struct __timespec64 *abstime)
{ {
return __pthread_clockjoin_ex (threadid, thread_return, return __pthread_clockjoin_ex (threadid, thread_return,
CLOCK_REALTIME, abstime, true); CLOCK_REALTIME, abstime, true);
} }
#if __TIMESIZE != 64
libc_hidden_def (__pthread_timedjoin_np64)
int
__pthread_timedjoin_np (pthread_t threadid, void **thread_return,
const struct timespec *abstime)
{
struct __timespec64 ts64 = valid_timespec_to_timespec64 (*abstime);
return __pthread_timedjoin_np64 (threadid, thread_return, &ts64);
}
#endif
weak_alias (__pthread_timedjoin_np, pthread_timedjoin_np) weak_alias (__pthread_timedjoin_np, pthread_timedjoin_np)

View File

@ -467,4 +467,56 @@ futex_unlock_pi (unsigned int *futex_word, int private)
} }
} }
#ifndef __NR_futex_time64
# define __NR_futex_time64 __NR_futex
#endif
static __always_inline int
futex_timed_wait_cancel64 (pid_t *tidp, pid_t tid,
const struct __timespec64 *timeout, int private)
{
int err = INTERNAL_SYSCALL_CANCEL (futex_time64, tidp,
__lll_private_flag
(FUTEX_WAIT, private), tid, timeout);
#ifndef __ASSUME_TIME64_SYSCALLS
if (err == -ENOSYS)
{
if (in_time_t_range (timeout->tv_sec))
{
struct timespec ts32 = valid_timespec64_to_timespec (*timeout);
err = INTERNAL_SYSCALL_CANCEL (futex, tidp,
__lll_private_flag (FUTEX_WAIT,
private),
tid, &ts32);
}
else
err = -EOVERFLOW;
}
#endif
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
case -EDEADLK:
case -ENOSYS:
case -EOVERFLOW: /* Passed absolute timeout uses 64 bit time_t type, but
underlying kernel does not support 64 bit time_t futex
syscalls. */
case -EPERM: /* The caller is not allowed to attach itself to the futex.
Used to check if PI futexes are supported by the
kernel. */
return -err;
case -EINVAL: /* Either due to wrong alignment or due to the timeout not
being normalized. Must have been caused by a glibc or
application bug. */
case -EFAULT: /* Must have been caused by a glibc or application bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
#endif /* futex-internal.h */ #endif /* futex-internal.h */