[RFC,07/52] Y2038: add function __clock_gettime64
Commit Message
Note: __clock_gettime64 is implemented in VDSO.
Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---
include/time.h | 8 ++++++
sysdeps/unix/clock_gettime.c | 46 ++++++++++++++++++++++++++++++++
sysdeps/unix/sysv/linux/arm/Versions | 3 +++
sysdeps/unix/sysv/linux/arm/init-first.c | 15 +++++++++++
sysdeps/unix/sysv/linux/arm/libc-vdso.h | 1 +
sysdeps/unix/sysv/linux/clock_gettime.c | 44 ++++++++++++++++++++++++++++++
6 files changed, 117 insertions(+)
@@ -20,6 +20,11 @@ libc_hidden_proto (localtime)
libc_hidden_proto (strftime)
libc_hidden_proto (strptime)
+/* Indicates whether the underlying kernel has 64-bit time support.
+ This is required for e.g. librt, which cannot directly check the
+ flag variable that init-first.c sets when detecting support. */
+extern int __y2038_kernel_support (void);
+
#if BYTE_ORDER == BIG_ENDIAN
struct __timespec64
{
@@ -43,6 +48,9 @@ extern __typeof (clock_settime) __clock_settime;
extern __typeof (clock_nanosleep) __clock_nanosleep;
extern __typeof (clock_getcpuclockid) __clock_getcpuclockid;
+extern int __clock_gettime64 (clockid_t __clock_id,
+ struct __timespec64 *__tp) __THROW;
+
/* Now define the internal interfaces. */
struct tm;
@@ -134,3 +134,49 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp)
}
weak_alias (__clock_gettime, clock_gettime)
libc_hidden_def (__clock_gettime)
+
+/* Get current value of CLOCK and store it in TP, 64-bit version. */
+int
+__clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
+{
+ int retval = -1;
+
+ switch (clock_id)
+ {
+#ifdef SYSDEP_GETTIME64
+ SYSDEP_GETTIME64;
+#endif
+
+#ifndef HANDLED_REALTIME
+ case CLOCK_REALTIME:
+ {
+ struct timeval tv;
+ retval = gettimeofday (&tv, NULL);
+ if (retval == 0)
+ TIMEVAL_TO_TIMESPEC (&tv, tp);
+ }
+ break;
+#endif
+
+ default:
+#ifdef SYSDEP_GETTIME64_CPU
+ SYSDEP_GETTIME64_CPU (clock_id, tp);
+#endif
+#if HP_TIMING_AVAIL
+ if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
+ == CLOCK_THREAD_CPUTIME_ID)
+ retval = hp_timing_gettime (clock_id, tp);
+ else
+#endif
+ __set_errno (EINVAL);
+ break;
+
+#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME
+ case CLOCK_PROCESS_CPUTIME_ID:
+ retval = hp_timing_gettime (clock_id, tp);
+ break;
+#endif
+ }
+
+ return retval;
+}
@@ -27,5 +27,8 @@ libc {
__localtime64; __localtime64_r;
__mktime64; __timelocal64_r;
__timegm64;
+ __clock_gettime64;
+ __vdso_clock_gettime64;
+ __y2038_kernel_support;
}
}
@@ -23,6 +23,14 @@
int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *) attribute_hidden;
int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+long (*VDSO_SYMBOL(clock_gettime64)) (clockid_t, struct __timespec64 *);
+
+int __y2038_linux_support;
+
+int __y2038_kernel_support (void)
+{
+ return __y2038_linux_support;
+}
static inline void
_libc_vdso_platform_setup (void)
@@ -36,6 +44,13 @@ _libc_vdso_platform_setup (void)
p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
PTR_MANGLE (p);
VDSO_SYMBOL (clock_gettime) = p;
+
+ /* (aaribaud) TODO: map to version where clock_gettime64 officially appears */
+ p = _dl_vdso_vsym ("__vdso_clock_gettime64", NULL);
+ PTR_MANGLE (p);
+ VDSO_SYMBOL (clock_gettime64) = p;
+
+ __y2038_linux_support = (p != NULL) ? 1 : 0;
}
# define VDSO_SETUP _libc_vdso_platform_setup
@@ -27,6 +27,7 @@
extern int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *)
attribute_hidden;
extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+extern long (*VDSO_SYMBOL(clock_gettime64)) (clockid_t, struct __timespec64 *);
#endif
@@ -44,4 +44,48 @@
break
#define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */
+/* 64-bit versions */
+
+/* The REALTIME and MONOTONIC clock are definitely supported in the
+ kernel. */
+#define SYSDEP_GETTIME64 \
+ SYSDEP_GETTIME64_CPUTIME; \
+ case CLOCK_REALTIME: \
+ case CLOCK_MONOTONIC: \
+ if (__y2038_linux_support) \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp); \
+ } \
+ else \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ tp->tv_sec = ts32.tv_sec; \
+ tp->tv_nsec = ts32.tv_nsec; \
+ tp->tv_pad = 0; \
+ } \
+ } \
+ break
+
+#define SYSDEP_GETTIME64_CPU(clock_id, tp) \
+ if (__y2038_linux_support) \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp); \
+ } \
+ else \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ tp->tv_sec = ts32.tv_sec; \
+ tp->tv_nsec = ts32.tv_nsec; \
+ tp->tv_pad = 0; \
+ } \
+ } \
+ break
+#define SYSDEP_GETTIME64_CPUTIME \
+ struct timespec ts32; \
+ extern int __y2038_linux_support;
+
#include <sysdeps/unix/clock_gettime.c>