[RFC,v4,03/24] sysdeps/gettimeofday: Use clock_gettime64 if avaliable

Message ID 1561c94daae983eb2380b9579d737146505f1a6f.1565398513.git.alistair.francis@wdc.com
State New, archived
Headers

Commit Message

Alistair Francis Aug. 10, 2019, 12:59 a.m. UTC
  Not all architectures support the obsolete gettimeofday so use the
newer clock_gettime64 syscall if it is avaliable. This fixes RV32
build issues.

This has the side effect of not setting the struct timezone *tz variable
if __ASSUME_TIME64_SYSCALLS or __NR_clock_gettime64 is defined!!!

The struct timezone *tz variable contaions information on the current
timezone, in this structure:
    struct timezone {
        int tz_minuteswest;     /* minutes west of Greenwich */
        int tz_dsttime;         /* type of DST correction */
    };

On 32-bit systems with __ARCH_WANT_TIME32_SYSCALLS not defined there is
no way way to get the struct timezone via a syscall. AFAIK there are no
plans to add suppor to a future kernel.

The Linux documentation says that "The use of the timezone structure
is obsolete; the tz argument should normally be specified as NULL."

Most callers of gettimeofday() don't use the timezone data, see
example code from Debian below.

If __ASSUME_TIME64_SYSCALLS and __NR_clock_gettime64 are not defined
then struct timezone *tz will be set as usual.

Example code from Debian:
struct timeval my_gettime(void)
{
     struct timezone tz_ignored;
     struct timeval tv;
     gettimeofday(&tv, &tz_ignored);
     return tv;
}

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 ChangeLog                              |  1 +
 sysdeps/unix/sysv/linux/gettimeofday.c | 51 ++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)
  

Comments

Joseph Myers Aug. 12, 2019, 5:27 p.m. UTC | #1
On Fri, 9 Aug 2019, Alistair Francis wrote:

> The Linux documentation says that "The use of the timezone structure
> is obsolete; the tz argument should normally be specified as NULL."

The relevant information to include in commit messages here isn't what the 
documentation says, it's what the interfaces actually do, as detailed in 
<https://sourceware.org/ml/libc-alpha/2019-07/msg00574.html>.

>  __gettimeofday (struct timeval *tv, struct timezone *tz)

> +#ifdef __ASSUME_TIME64_SYSCALLS
> +  long int ret;
> +  struct timespec now;
> +
> +  ret = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
> +                         &now);

This is using a timespec (possibly 32-bit) with a syscall that requires 
the 64-bit version.  You need to address such issues throughout the patch 
series.  As illustrated here, it's not just cases where you have a 
mismatch with the function interface; you need to make sure, in every 
case, that where you pass internal variables to 64-bit time syscalls they 
have the correct type as well.

> +#else
> +# ifdef __NR_clock_nanosleep_time64

No, this code isn't using clock_nanosleep_time64.  The #ifdef should be 
for the syscall it actually uses.
  

Patch

diff --git a/ChangeLog b/ChangeLog
index aab4469b3d4..82a2cdc746d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1424,6 +1424,7 @@ 
 	* nptl/thrd_sleep.c: Use clock_nanosleep_time64 instead of nanosleep.
 	* sysdeps/unix/sysv/linux/nanosleep.c: Likewise.
 	* sysdeps/unix/sysv/linux/nanosleep_nocancel.c: Likewise.
+	* sysdeps/unix/sysv/linux/gettimeofday.c: Use clock_gettime64 syscall for gettimeofday.
 
 2019-06-20  Dmitry V. Levin  <ldv@altlinux.org>
 	    Florian Weimer  <fweimer@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/gettimeofday.c b/sysdeps/unix/sysv/linux/gettimeofday.c
index a74f03825a5..bfbe7216198 100644
--- a/sysdeps/unix/sysv/linux/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/gettimeofday.c
@@ -32,7 +32,58 @@ 
 int
 __gettimeofday (struct timeval *tv, struct timezone *tz)
 {
+#ifdef __ASSUME_TIME64_SYSCALLS
+  long int ret;
+  struct timespec now;
+
+  ret = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
+                         &now);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      /* Convert from timespec to timeval */
+      tv->tv_sec = now.tv_sec;
+      tv->tv_usec = now.tv_nsec / 1000;
+    }
+  return ret;
+#else
+# ifdef __NR_clock_nanosleep_time64
+  long int ret;
+#  if __TIMESIZE == 64
+  ret = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
+                         &now);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      /* Convert from timespec to timeval */
+      tv->tv_sec = now.tv_sec;
+      tv->tv_usec = now.tv_nsec / 1000;
+      return ret;
+    }
+#  else
+  struct __timespec64 now;
+
+  ret = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
+                         &now);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      /* Convert from timespec to timeval */
+      tv->tv_sec = now.tv_sec;
+      tv->tv_usec = now.tv_nsec / 1000;
+      return ret;
+    }
+#  endif /* __TIMESIZE == 64 */
+# endif /* __NR_clock_nanosleep_time64 */
+# if __TIMESIZE == 64
+  if (! in_time_t_range (tv->tv_sec))
+    {
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+# endif /* __TIMESIZE == 64 */
   return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+#endif
 }
 libc_hidden_def (__gettimeofday)
 weak_alias (__gettimeofday, gettimeofday)