[RFC,10/52] Y2038: add function __clock_nanosleep64

Message ID 20170907224219.12483-11-albert.aribaud@3adev.fr
State New
Headers show
Series
  • Make GLIBC Y2038-proof
Related show

Commit Message

Albert ARIBAUD Sept. 7, 2017, 10:41 p.m.
Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---
 include/time.h                            |  3 ++
 sysdeps/unix/sysv/linux/arm/Versions      |  1 +
 sysdeps/unix/sysv/linux/clock_nanosleep.c | 87 ++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 1 deletion(-)

Patch

diff --git a/include/time.h b/include/time.h
index 00bdb2853a..90c1385d13 100644
--- a/include/time.h
+++ b/include/time.h
@@ -54,6 +54,9 @@  extern int __clock_settime64 (clockid_t __clock_id,
 			       const struct __timespec64 *__tp) __THROW;
 extern int __clock_getres64 (clockid_t __clock_id,
 			      struct __timespec64 *__res) __THROW;
+extern int __clock_nanosleep64 (clockid_t __clock_id, int __flags,
+				const struct __timespec64 *__req,
+				struct __timespec64 *__rem);
 
 /* Now define the internal interfaces.  */
 struct tm;
diff --git a/sysdeps/unix/sysv/linux/arm/Versions b/sysdeps/unix/sysv/linux/arm/Versions
index 4b03cce526..fd94c63672 100644
--- a/sysdeps/unix/sysv/linux/arm/Versions
+++ b/sysdeps/unix/sysv/linux/arm/Versions
@@ -32,5 +32,6 @@  libc {
     __y2038_kernel_support;
     __clock_settime64;
     __clock_getres64;
+    __clock_nanosleep64;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 93bc4cf47e..7d00176c3e 100644
--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
+++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
@@ -21,7 +21,6 @@ 
 #include <sysdep-cancel.h>
 #include "kernel-posix-cpu-timers.h"
 
-
 /* We can simply use the syscall.  The CPU clocks are not supported
    with this function.  */
 int
@@ -52,3 +51,89 @@  __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
 	  ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
 }
 weak_alias (__clock_nanosleep, clock_nanosleep)
+
+/* 64-bit time version */
+
+extern int __y2038_linux_support;
+
+int
+__clock_nanosleep64 (clockid_t clock_id, int flags,
+		   const struct __timespec64 *req,
+                   struct __timespec64 *rem)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  int r;
+  struct __timespec64 req64;
+  struct timespec req32, rem32;
+
+  if (clock_id == CLOCK_THREAD_CPUTIME_ID)
+    return EINVAL;
+  if (clock_id == CLOCK_PROCESS_CPUTIME_ID)
+    clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);
+
+  if (SINGLE_THREAD_P)
+    {
+      if (__y2038_linux_support)
+        {
+          req64.tv_sec = req->tv_sec;
+          req64.tv_nsec = req->tv_nsec;
+          req64.tv_pad = 0;
+          r = INTERNAL_SYSCALL (clock_nanosleep64, err, 4, clock_id, flags,
+                                &req64, rem);
+        }
+      else if (req->tv_sec > INT_MAX)
+        r = EOVERFLOW;
+      else
+        {
+          req32.tv_sec = req->tv_sec;
+          req32.tv_nsec = req->tv_nsec;
+          r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags,
+                                &req32, &rem32);
+          if (r == EINTR && rem != NULL && flags != TIMER_ABSTIME)
+            {
+              rem->tv_sec = rem32.tv_sec;
+              rem->tv_nsec = rem32.tv_nsec;
+              rem->tv_pad = 0;
+            }
+        }
+    }
+  else
+    {
+      int oldstate = LIBC_CANCEL_ASYNC ();
+
+      if (__y2038_linux_support)
+        {
+          req64.tv_sec = req->tv_sec;
+          req64.tv_nsec = req->tv_nsec;
+          req64.tv_pad = 0;
+          r = INTERNAL_SYSCALL (clock_nanosleep64, err, 4, clock_id, flags,
+                                &req64, rem);
+        }
+      else if (req->tv_sec > INT_MAX)
+        r = EOVERFLOW;
+      else
+        {
+          req32.tv_sec = req->tv_sec;
+          req32.tv_nsec = req->tv_nsec;
+          r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags,
+                                &req32, &rem32);
+          if (r == EINTR && rem != NULL && flags != TIMER_ABSTIME)
+            {
+              rem->tv_sec = rem32.tv_sec;
+              rem->tv_nsec = rem32.tv_nsec;
+              rem->tv_pad = 0;
+            }
+        }
+      
+      LIBC_CANCEL_RESET (oldstate);
+    }
+
+  if (INTERNAL_SYSCALL_ERROR_P (r, err))
+    {
+      return INTERNAL_SYSCALL_ERRNO (r, err);
+    }
+  else
+    {
+      return 0;
+    }
+}