diff mbox

[[PATCH,RFC,2] 16/63] Y2038: add function __clock_settime64

Message ID 20180418201819.15952-17-albert.aribaud@3adev.fr
State New
Headers show

Commit Message

Albert ARIBAUD April 18, 2018, 8:17 p.m. UTC
---
 include/time.h                          |  2 ++
 sysdeps/unix/clock_settime.c            | 56 +++++++++++++++++++++++++++++-
 sysdeps/unix/sysv/linux/clock_settime.c | 60 +++++++++++++++++++++++++++++++++
 time/Versions                           |  1 +
 4 files changed, 118 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/include/time.h b/include/time.h
index e085fa5162..8101b638c6 100644
--- a/include/time.h
+++ b/include/time.h
@@ -35,6 +35,8 @@  extern __typeof (clock_getcpuclockid) __clock_getcpuclockid;
 
 extern int __clock_gettime64 (clockid_t __clock_id,
 			      struct __timespec64 *__tp) __THROW;
+extern int __clock_settime64 (clockid_t __clock_id,
+			       const struct __timespec64 *__tp) __THROW;
 
 /* Now define the internal interfaces.  */
 struct tm;
diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c
index 38813eddf7..15626ee3e9 100644
--- a/sysdeps/unix/clock_settime.c
+++ b/sysdeps/unix/clock_settime.c
@@ -68,8 +68,62 @@  hp_timing_settime (clockid_t clock_id, const struct timespec *tp)
 }
 #endif
 
+/* Set CLOCK to value TP, 64-bit Y2038-safe version.  */
+int
+__clock_settime64 (clockid_t clock_id, const struct __timespec64 *tp)
+{
+  int retval = -1;
+
+  /* Make sure the time cvalue is OK.  */
+  if (! IS_VALID_NANOSECONDS(tp->tv_nsec))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  switch (clock_id)
+    {
+#define HANDLE_REALTIME64 \
+      do {								      \
+	struct timeval tv;						      \
+	TIMESPEC_TO_TIMEVAL (&tv, tp);					      \
+									      \
+	retval = __settimeofday (&tv, NULL);				      \
+      } while (0)
+
+#ifdef SYSDEP_SETTIME64
+      SYSDEP_SETTIME64;
+#endif
+
+#ifndef HANDLED_REALTIME
+    case CLOCK_REALTIME:
+      HANDLE_REALTIME64;
+      break;
+#endif
+
+    default:
+#ifdef SYSDEP_SETTIME64_CPU
+      SYSDEP_SETTIME64_CPU;
+#endif
+#ifndef HANDLED_CPUTIME
+# if HP_TIMING_AVAIL
+      if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID
+	  || CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID)
+	retval = hp_timing_settime (clock_id, tp);
+      else
+# endif
+	{
+	  __set_errno (EINVAL);
+	  retval = -1;
+	}
+#endif
+      break;
+    }
+
+  return retval;
+}
 
-/* Set CLOCK to value TP.  */
+/* Set CLOCK to value TP, 64-bit Y2038-unsafe version.  */
 int
 __clock_settime (clockid_t clock_id, const struct timespec *tp)
 {
diff --git a/sysdeps/unix/sysv/linux/clock_settime.c b/sysdeps/unix/sysv/linux/clock_settime.c
index 5f3f22f74b..70ddb9e5ff 100644
--- a/sysdeps/unix/sysv/linux/clock_settime.c
+++ b/sysdeps/unix/sysv/linux/clock_settime.c
@@ -35,4 +35,64 @@ 
 #define SYSDEP_SETTIME_CPU \
   retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp)
 
+/* 64-bit time version */
+
+#ifdef __NR_clock_settime64
+/* We know the clock_gettime64 syscall, so use it or else clock_gettime */
+
+extern int __y2038_linux_support;
+
+#define SYSDEP_SETTIME64 \
+  SYSDEP_SETTIME64_CPUTIME;						      \
+  case CLOCK_REALTIME:							      \
+    if (__y2038_linux_support)						      \
+      {									      \
+        ts64.tv_sec = tp->tv_sec;					      \
+        ts64.tv_nsec = tp->tv_nsec;					      \
+        ts64.tv_pad = 0;						      \
+        retval = INLINE_SYSCALL (clock_settime64, 2, clock_id, &ts64);	      \
+      }									      \
+    else                         					      \
+      {									      \
+        retval = -1;                                                          \
+        __set_errno (EOVERFLOW);                                              \
+      }									      \
+    if (retval == -1 && errno == ENOSYS)				      \
+      {									      \
+        if (! fits_in_time_t(tp->tv_sec))                                     \
+         {                                                                    \
+           __set_errno (EOVERFLOW);                                           \
+         }                                                                    \
+        else                                                                  \
+          {                                                                   \
+            valid_timespec64_to_timespec(tp, &ts32);  			      \
+            retval = INLINE_SYSCALL (clock_settime, 2, clock_id, &ts32);      \
+          }                                                                   \
+      }                                                                       \
+    break
+#define SYSDEP_SETTIME64_CPUTIME \
+  struct __timespec64 ts64;						      \
+  struct timespec ts32;
+
+#else
+/* We don't know the clock_gettime64 syscall, so only use clock_gettime */
+
+#define SYSDEP_SETTIME64 \
+  SYSDEP_SETTIME64_CPUTIME;						      \
+  case CLOCK_REALTIME:							      \
+    if (! fits_in_time_t(tp->tv_sec))                                         \
+     {                                                                        \
+       __set_errno (EOVERFLOW);                                               \
+     }                                                                        \
+    else                                                                      \
+      {                                                                       \
+        valid_timespec64_to_timespec(tp, &ts32);  			      \
+        retval = INLINE_SYSCALL (clock_settime, 2, clock_id, &ts32);          \
+      }                                                                       \
+    break
+#define SYSDEP_SETTIME64_CPUTIME \
+  struct timespec ts32;
+
+#endif
+
 #include <sysdeps/unix/clock_settime.c>
diff --git a/time/Versions b/time/Versions
index 27c46fc023..a00184daae 100644
--- a/time/Versions
+++ b/time/Versions
@@ -75,5 +75,6 @@  libc {
     __clock_gettime64;
     __vdso_clock_gettime64;
     __y2038_kernel_support;
+    __clock_settime64;
   }
 }