Y2038: add function __clock_getres_time64

Message ID 20180919081443.30910-1-albert.aribaud@3adev.fr
State New, archived
Headers

Commit Message

Albert ARIBAUD Sept. 19, 2018, 8:14 a.m. UTC
  * include/time.h (__clock_getres_time64): Add.
* sysdeps/posix/clock_getres.c (hp_timing_getres): Use
  struct __timespec64.
* sysdeps/posix/clock_getres.c (realtime_getres): Likewise.
* sysdeps/posix/clock_getres.c (__clock_getres_time64): Add.
* sysdeps/posix/clock_getres.c Use SYSDEP_GETRES64.
* sysdeps/posix/clock_getres.c Use SYSDEP_GETRES_CPU64.
* sysdeps/posix/clock_getres.c (__clock_getres):
  Use __clock_getres_time64.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES32): Add.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES64): Likewise.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSDEP_GETRES64): Likewise.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSDEP_GETRES_CPU64): Likewise.
---

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_getres_time64
syscall being provided by the kernel at build as well
as run time.

This patch is part of the Y2038 patch series, which is available at
<https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/aaribaud/y2038>.
Warning: this branch may be rebased on current master and/or updated based on
feedback from the list at any time.

 include/time.h                         |  2 +
 sysdeps/posix/clock_getres.c           | 31 +++++++++----
 sysdeps/unix/sysv/linux/clock_getres.c | 61 ++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 9 deletions(-)
  

Comments

Joseph Myers Sept. 19, 2018, 2:49 p.m. UTC | #1
On Wed, 19 Sep 2018, Albert ARIBAUD (3ADEV) wrote:

> @@ -23,12 +23,11 @@
>  #include <sys/param.h>
>  #include <libc-internal.h>
>  
> -
>  #if HP_TIMING_AVAIL

Please avoid spurious diff hunks adding or removing whitespace like this.

> +int
> +__clock_getres (clockid_t clock_id, struct timespec *res)
> +{
> +  struct __timespec64 ts64;
> +  int retval = __clock_getres_time64 (clock_id, &ts64);
> +  if (retval == 0)
> +    {
> +      // We assume we never run with a CPU clock period greater than
> +      // 2**31 seconds and therefore we do not check the seconds field

Comments in glibc should use /* */, not //.  All comments should end with 
".".  Please check for and fix such issues throughout the patch series.  
There are several others in this patch.

> +      res->tv_sec = ts64.tv_sec;
> +      res->tv_nsec = ts64.tv_nsec;
> +    }
> +  return retval;

Generically, it is important that on systems where time_t is already 
64-bit, no additional conversion code or function calls get built into 
glibc; the abstractions used at the source code level must be completely 
optimized away in that case (whether through use of #if etc. to control 
what gets built and what functions are aliases of what other functions, or 
through arranging the code so it can and does all get inlined in that 
case, etc.).

Please, in each patch posting, include details of the configurations for 
which it was tested for the full glibc testsuite (which should include at 
least one 32-bit and one 64-bit configuration).  You should also include 
explicit confirmation of how the code ensures no additional speed or size 
overhead for configurations where time_t is already 64-bit.
  

Patch

diff --git a/include/time.h b/include/time.h
index 5a658223ce..d5bddeb23f 100644
--- a/include/time.h
+++ b/include/time.h
@@ -28,6 +28,8 @@  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;
+extern int __clock_getres_time64 (clockid_t __clock_id,
+				  struct __timespec64 *__res) __THROW;
 
 /* Now define the internal interfaces.  */
 struct tm;
diff --git a/sysdeps/posix/clock_getres.c b/sysdeps/posix/clock_getres.c
index e7924e0891..6b0d5da23c 100644
--- a/sysdeps/posix/clock_getres.c
+++ b/sysdeps/posix/clock_getres.c
@@ -23,12 +23,11 @@ 
 #include <sys/param.h>
 #include <libc-internal.h>
 
-
 #if HP_TIMING_AVAIL
 static long int nsec;		/* Clock frequency of the processor.  */
 
 static int
-hp_timing_getres (struct timespec *res)
+hp_timing_getres (struct __timespec64 *res)
 {
   if (__glibc_unlikely (nsec == 0))
     {
@@ -56,7 +55,7 @@  hp_timing_getres (struct timespec *res)
 #endif
 
 static inline int
-realtime_getres (struct timespec *res)
+realtime_getres (struct __timespec64 *res)
 {
   long int clk_tck = __sysconf (_SC_CLK_TCK);
 
@@ -73,17 +72,16 @@  realtime_getres (struct timespec *res)
   return -1;
 }
 
-
 /* Get resolution of clock.  */
 int
-__clock_getres (clockid_t clock_id, struct timespec *res)
+__clock_getres_time64 (clockid_t clock_id, struct __timespec64 *res)
 {
   int retval = -1;
 
   switch (clock_id)
     {
-#ifdef SYSDEP_GETRES
-      SYSDEP_GETRES;
+#ifdef SYSDEP_GETRES64
+      SYSDEP_GETRES64;
 #endif
 
 #ifndef HANDLED_REALTIME
@@ -93,8 +91,8 @@  __clock_getres (clockid_t clock_id, struct timespec *res)
 #endif	/* handled REALTIME */
 
     default:
-#ifdef SYSDEP_GETRES_CPU
-      SYSDEP_GETRES_CPU;
+#ifdef SYSDEP_GETRES_CPU64
+      SYSDEP_GETRES_CPU64;
 #endif
 #if HP_TIMING_AVAIL
       if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
@@ -115,4 +113,19 @@  __clock_getres (clockid_t clock_id, struct timespec *res)
 
   return retval;
 }
+
+int
+__clock_getres (clockid_t clock_id, struct timespec *res)
+{
+  struct __timespec64 ts64;
+  int retval = __clock_getres_time64 (clock_id, &ts64);
+  if (retval == 0)
+    {
+      // We assume we never run with a CPU clock period greater than
+      // 2**31 seconds and therefore we do not check the seconds field
+      res->tv_sec = ts64.tv_sec;
+      res->tv_nsec = ts64.tv_nsec;
+    }
+  return retval;
+}
 weak_alias (__clock_getres, clock_getres)
diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c
index 5d94f59afe..6b895f1e87 100644
--- a/sysdeps/unix/sysv/linux/clock_getres.c
+++ b/sysdeps/unix/sysv/linux/clock_getres.c
@@ -19,6 +19,7 @@ 
 #include <sysdep.h>
 #include <errno.h>
 #include <time.h>
+#include <y2038-support.h>
 #include "kernel-posix-cpu-timers.h"
 
 #ifdef HAVE_CLOCK_GETRES_VSYSCALL
@@ -48,4 +49,64 @@ 
 #define SYSDEP_GETRES_CPU SYSCALL_GETRES
 #define SYSDEP_GETRES_CPUTIME	/* Default catches them too.  */
 
+/* The 64-bit version */
+
+// Call the 32-bit syscall and convert to 64-bit time
+#define SYSCALL_GETRES32 \
+  retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, &ts32);		\
+  if (retval==0)							\
+    {									\
+      timespec_to_timespec64(&ts32, res);				\
+      res->tv_pad = 0;							\
+    }
+
+#ifdef __NR_clock_getres_time64
+
+/* We are building with a 64-bit-time getres syscall */
+
+#define SYSCALL_GETRES64 \
+  if (__y2038_linux_support > 0)					\
+    {									\
+      retval = INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res);	\
+      if (retval == -1 && errno == ENOSYS)				\
+	{								\
+	  __y2038_linux_support = -1;					\
+	  SYSCALL_GETRES32;						\
+	}								\
+    }									\
+  else									\
+    {									\
+      SYSCALL_GETRES32;							\
+    }									\
+  break
+
+#else
+
+/* We are building without a 64-bit-time getres syscall */
+
+#define SYSCALL_GETRES64 \
+  SYSCALL_GETRES32;							\
+  break
+
+#endif
+
+/* The REALTIME and MONOTONIC clock are definitely supported in the
+   kernel.  */
+#define SYSDEP_GETRES64							\
+  SYSDEP_GETRES_CPUTIME64						\
+  case CLOCK_REALTIME:							\
+  case CLOCK_MONOTONIC:							\
+  case CLOCK_MONOTONIC_RAW:						\
+  case CLOCK_REALTIME_COARSE:						\
+  case CLOCK_MONOTONIC_COARSE:						\
+    SYSCALL_GETRES64
+
+/* We handled the REALTIME clock here.  */
+#define HANDLED_REALTIME64	1
+#define HANDLED_CPUTIME64	1
+
+#define SYSDEP_GETRES_CPU64 SYSCALL_GETRES64
+#define SYSDEP_GETRES_CPUTIME64 \
+  struct timespec ts32;
+
 #include <sysdeps/posix/clock_getres.c>