[[PATCH,RFC,2] 13/63] Y2038: add function __clock_gettime64
Commit Message
The Unix implementation uses 32-bit calls and converts to
64-bit time.
The Linux implementation uses the 64-bit time syscall if
available, otherwise it falls back to 32-bit syscall and
conversion.
This implementation depends on the clock_gettime64 syscall
being provided in the kernel headers at build time.
---
include/time.h | 8 ++++
sysdeps/unix/clock_gettime.c | 54 ++++++++++++++++++++++
sysdeps/unix/sysv/linux/clock_gettime.c | 81 +++++++++++++++++++++++++++++++++
time/Versions | 3 ++
4 files changed, 146 insertions(+)
@@ -21,6 +21,11 @@ libc_hidden_proto (strptime)
libc_hidden_proto (__localtime64)
+/* 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);
+
extern __typeof (clock_getres) __clock_getres;
extern __typeof (clock_gettime) __clock_gettime;
libc_hidden_proto (__clock_gettime)
@@ -28,6 +33,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,57 @@ __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;
+#if HP_TIMING_AVAIL || !defined HANDLED_REALTIME
+ struct timeval tv32;
+#endif
+
+ switch (clock_id)
+ {
+#ifdef SYSDEP_GETTIME64
+ SYSDEP_GETTIME64;
+#endif
+
+#ifndef HANDLED_REALTIME
+ case CLOCK_REALTIME:
+ {
+ retval = gettimeofday (&tv32, NULL);
+ if (retval == 0)
+ valid_timeval_to_timespec64 (&tv32, 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, &tv32);
+ if (retval == 0)
+ valid_timeval_to_timespec64 (&tv32, 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, &tv32);
+ if (retval == 0)
+ valid_timeval_to_timespec64 (&tv32, tp);
+ break;
+#endif
+ }
+
+ return retval;
+}
@@ -44,4 +44,85 @@
break
#define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */
+/* 64-bit versions */
+
+/* Check that we are builing on a 64-bit-time kernel, otherwise
+ clock_gettime64 syscall will fail to compile */
+#ifdef __NR_clock_gettime64
+
+/* 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 = -1; \
+ __set_errno(ENOSYS); \
+ } \
+ if (retval == -1 && errno == ENOSYS) \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ valid_timespec_to_timespec64(&ts32, tp); \
+ } \
+ } \
+ break
+
+#define SYSDEP_GETTIME64_CPU(clock_id, tp) \
+ if (__y2038_linux_support) \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp); \
+ } \
+ else \
+ { \
+ retval = -1; \
+ __set_errno(ENOSYS); \
+ } \
+ if (retval == -1 && errno == ENOSYS) \
+ { \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ valid_timespec_to_timespec64(&ts32, tp); \
+ } \
+ } \
+ break
+#define SYSDEP_GETTIME64_CPUTIME \
+ struct timespec ts32; \
+ extern int __y2038_linux_support;
+
+#else
+
+/* The REALTIME and MONOTONIC clock are definitely supported in the
+ kernel. */
+#define SYSDEP_GETTIME64 \
+ SYSDEP_GETTIME64_CPUTIME; \
+ case CLOCK_REALTIME: \
+ case CLOCK_MONOTONIC: \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ valid_timespec_to_timespec64(&ts32, tp); \
+ } \
+ break
+
+#define SYSDEP_GETTIME64_CPU(clock_id, tp) \
+ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
+ if (retval==0) \
+ { \
+ valid_timespec_to_timespec64(&ts32, tp); \
+ } \
+ break
+#define SYSDEP_GETTIME64_CPUTIME \
+ struct timespec ts32; \
+
+#endif
+
#include <sysdeps/unix/clock_gettime.c>
@@ -72,5 +72,8 @@ libc {
__localtime64; __localtime64_r;
__mktime64; __timelocal64_r;
__timegm64;
+ __clock_gettime64;
+ __vdso_clock_gettime64;
+ __y2038_kernel_support;
}
}