diff mbox series

[[PATCH,RFC,2] 13/63] Y2038: add function __clock_gettime64

Message ID 20180418201819.15952-14-albert.aribaud@3adev.fr
State New
Headers show
Series [[PATCH,RFC,2] 13/63] Y2038: add function __clock_gettime64 | expand

Commit Message

Albert ARIBAUD (3ADEV) April 18, 2018, 8:17 p.m. UTC
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(+)
diff mbox series

Patch

diff --git a/include/time.h b/include/time.h
index 16286178e1..e085fa5162 100644
--- a/include/time.h
+++ b/include/time.h
@@ -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;
 
diff --git a/sysdeps/unix/clock_gettime.c b/sysdeps/unix/clock_gettime.c
index 96df78ab1e..f8e96487e3 100644
--- a/sysdeps/unix/clock_gettime.c
+++ b/sysdeps/unix/clock_gettime.c
@@ -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;
+}
diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
index d837fa36b1..a0da479ea6 100644
--- a/sysdeps/unix/sysv/linux/clock_gettime.c
+++ b/sysdeps/unix/sysv/linux/clock_gettime.c
@@ -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>
diff --git a/time/Versions b/time/Versions
index 7cfae8760c..27c46fc023 100644
--- a/time/Versions
+++ b/time/Versions
@@ -72,5 +72,8 @@  libc {
     __localtime64; __localtime64_r;
     __mktime64; __timelocal64_r;
     __timegm64;
+    __clock_gettime64;
+    __vdso_clock_gettime64;
+    __y2038_kernel_support;
   }
 }