Patchwork [v2] y2038: linux: Provide __clock_getres64 implementation

login
register
mail settings
Submitter Lukasz Majewski
Date Oct. 20, 2019, 9:38 p.m.
Message ID <20191020213859.15952-1-lukma@denx.de>
Download mbox | patch
Permalink /patch/35193/
State New
Headers show

Comments

Lukasz Majewski - Oct. 20, 2019, 9:38 p.m.
This patch provides new __clock_getres64 explicit 64 bit function for
getting the resolution (precision) of specified clock ID. Moreover, a
32 bit version - __clock_getres has been refactored to internally use
__clock_getres64.

The __clock_getres is now supposed to be used on systems still supporting
32 bit time (__TIMESIZE != 64) - hence the necessary conversion from 64 bit
struct __timespec64 to struct timespec.

The new clock_getres_time64 syscall available from Linux 5.1+ has been used,
when applicable.
On systems which are not supporting clock_getres_time64 (as their
clock_getres supports 64 bit time ABI) the vDSO syscall is attempted.
On the contrary the non-vDSO syscall is used for clock_getres_time64 as
up till now the kernel is not providing such interface.

No additional checks (i.e. if tv_nsec value overflow) are performed on
values returned via clock_getres{_time64} syscall, as it is assumed that
the Linux kernel will either return 0 and provide correct value or error.

The check for tv_sec being out of range on systems still supporting 32 bit
time (__TIMESIZE != 64) without Y2038 time support is also omitted as it is
_very_ unlikely that we would have a timer with resolution which exceeds 32
bit time_t range.

Build tests:
- The code has been tested on x86_64/x86 (native compilation):
make PARALLELMFLAGS="-j8" && make xcheck PARALLELMFLAGS="-j8"

- The glibc has been build tested (make PARALLELMFLAGS="-j8") for
x86 (i386), x86_64-x32, and armv7

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

- Use of cross-test-ssh.sh for ARM (armv7):
  make PARALLELMFLAGS="-j8" test-wrapper='./cross-test-ssh.sh root@192.168.7.2' xcheck

Linux kernel, headers and minimal kernel version for glibc build test
matrix:
- Linux v5.1 (with clock_getres_time64) and glibc build with v5.1 as
  minimal kernel version (--enable-kernel="5.1.0")
  The __ASSUME_TIME64_SYSCALLS flag defined.

- Linux v5.1 and default minimal kernel version
  The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports
  clock_getres_time64 syscall.

- Linux v4.19 (no clock_getres_time64 support) with default minimal kernel
  version for contemporary glibc

  This kernel doesn't support clock_getres_time64 syscall, so the fallback
  to clock_getres is tested.

The above tests were performed with Y2038 redirection applied as well as
without (so the __TIMESIZE != 64 execution path is checked as well).

No regressions were observed.
---
Changes for v2:
- Replace timespec64_to_timespec () with valid_timespec64_to_timespec () as
  clock_getres() just reads the value from the kernel.
  Therefore one can assume that if the syscall returns 0, the value passed
  from the kernel is correct and no extra checks are necessary.
---
 include/time.h                         |  8 ++++++
 sysdeps/unix/sysv/linux/clock_getres.c | 38 ++++++++++++++++++++++++--
 2 files changed, 43 insertions(+), 3 deletions(-)
Paul Eggert - Oct. 21, 2019, 12:21 a.m.
On 10/20/19 2:38 PM, Lukasz Majewski wrote:
> +  if (! retval && res)
> +      *res = valid_timespec64_to_timespec (ts64);

The indenting is wrong in the 2nd line.
Lukasz Majewski - Oct. 21, 2019, 7:31 a.m.
Hi Paul,

> On 10/20/19 2:38 PM, Lukasz Majewski wrote:
> > +  if (! retval && res)
> > +      *res = valid_timespec64_to_timespec (ts64);  
> 
> The indenting is wrong in the 2nd line.

Ach... Thanks for spotting.


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Joseph Myers - Oct. 25, 2019, 9:28 p.m.
This patch is OK.

Patch

diff --git a/include/time.h b/include/time.h
index d93b16a781..8a21350233 100644
--- a/include/time.h
+++ b/include/time.h
@@ -133,6 +133,14 @@  extern int __clock_settime64 (clockid_t clock_id,
 libc_hidden_proto (__clock_settime64)
 #endif
 
+#if __TIMESIZE == 64
+# define __clock_getres64 __clock_getres
+#else
+extern int __clock_getres64 (clockid_t clock_id,
+                             struct __timespec64 *tp);
+libc_hidden_proto (__clock_getres64);
+#endif
+
 /* Compute the `struct tm' representation of T,
    offset OFFSET seconds east of UTC,
    and store year, yday, mon, mday, wday, hour, min, sec into *TP.
diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c
index 0b82759043..22762608be 100644
--- a/sysdeps/unix/sysv/linux/clock_getres.c
+++ b/sysdeps/unix/sysv/linux/clock_getres.c
@@ -19,21 +19,53 @@ 
 #include <sysdep.h>
 #include <errno.h>
 #include <time.h>
-#include "kernel-posix-cpu-timers.h"
 
 #ifdef HAVE_CLOCK_GETRES_VSYSCALL
 # define HAVE_VSYSCALL
 #endif
 #include <sysdep-vdso.h>
-
 #include <shlib-compat.h>
+#include <kernel-features.h>
 
 /* Get resolution of clock.  */
 int
-__clock_getres (clockid_t clock_id, struct timespec *res)
+__clock_getres64 (clockid_t clock_id, struct __timespec64 *res)
 {
+#ifdef __ASSUME_TIME64_SYSCALLS
+# ifndef __NR_clock_getres_time64
   return INLINE_VSYSCALL (clock_getres, 2, clock_id, res);
+# else
+  return INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res);
+# endif
+#else
+# ifdef __NR_clock_getres_time64
+  int ret = INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res);
+  if (ret == 0 || errno != ENOSYS)
+    return ret;
+# endif
+  struct timespec ts32;
+  int retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, &ts32);
+  if (! retval && res)
+    *res = valid_timespec_to_timespec64 (ts32);
+
+  return retval;
+#endif
+}
+
+#if __TIMESIZE != 64
+int
+__clock_getres (clockid_t clock_id, struct timespec *res)
+{
+  struct __timespec64 ts64;
+  int retval;
+
+  retval = __clock_getres64 (clock_id, &ts64);
+  if (! retval && res)
+      *res = valid_timespec64_to_timespec (ts64);
+
+  return retval;
 }
+#endif
 
 versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17);
 /* clock_getres moved to libc in version 2.17;