[RFC,v5,03/21] sysdeps/gettimeofday: Use clock_gettime64 if avaliable

Message ID 11c2a035bdd1abfced754902e88973639bdf8e12.1567097252.git.alistair.francis@wdc.com
State New, archived
Headers

Commit Message

Alistair Francis Aug. 29, 2019, 4:50 p.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.

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;
}

Arnd used Debian code search and found the following uses of struct timezone:

drivers/media/platform/vivid/vivid-rds-gen.c:
(sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c:
record->end_utc_bias = cpu_to_le16(sys_tz.tz_minuteswest * 60);
drivers/scsi/3w-9xxx.c: local_time = (u32)(ktime_get_real_seconds() -
(sys_tz.tz_minuteswest * 60));
drivers/scsi/3w-sas.c:  local_time = (u32)(ktime_get_real_seconds() -
(sys_tz.tz_minuteswest * 60));
drivers/scsi/aacraid/commsup.c: local_time = (now->tv_sec -
(sys_tz.tz_minuteswest * 60));
drivers/scsi/arcmsr/arcmsr_hba.c:
time64_to_tm(ktime_get_real_seconds(), -sys_tz.tz_minuteswest * 60,
&tm);
drivers/scsi/mvumi.c:           local_time = (time -
(sys_tz.tz_minuteswest * 60));
drivers/scsi/smartpqi/smartpqi_init.c:  time64_to_tm(local_time,
-sys_tz.tz_minuteswest * 60, &tm);
fs/affs/amigaffs.c:     secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365
+ 2) * 24 * 60 * 60);
fs/affs/inode.c:                         sys_tz.tz_minuteswest * 60;
fs/fat/misc.c:         sys_tz.tz_minuteswest) * SECS_PER_MIN;
fs/hfs/hfs_fs.h:        return ut + sys_tz.tz_minuteswest * 60;
fs/hfs/inode.c: HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60;
fs/hfs/sysdep.c:        diff = sys_tz.tz_minuteswest * 60 -
HFS_I(inode)->tz_secondswest;
fs/hpfs/hpfs_fn.h:      return t + sys_tz.tz_minuteswest * 60 +
hpfs_sb(s)->sb_timeshift;
fs/udf/udftime.c:       offset = -sys_tz.tz_minuteswest;
kernel/debug/kdb/kdb_main.c:            sys_tz.tz_minuteswest);
kernel/time/ntp.c:              adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
kernel/time/timekeeping.c:      if (sys_tz.tz_minuteswest != 0) {
kernel/time/vsyscall.c:         vdata[CS_HRES_COARSE].tz_minuteswest =
sys_tz.tz_minuteswest;
lib/vdso/gettimeofday.c:                tz->tz_minuteswest =
vd[CS_HRES_COARSE].tz_minuteswest;
net/netfilter/xt_time.c:                stamp -= 60 * sys_tz.tz_minuteswest;

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

	* sysdeps/unix/sysv/linux/gettimeofday.c: Use clock_gettime64 syscall
	for gettimeofday.
---
 sysdeps/unix/sysv/linux/gettimeofday.c | 59 +++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)
  

Patch

diff --git a/sysdeps/unix/sysv/linux/gettimeofday.c b/sysdeps/unix/sysv/linux/gettimeofday.c
index a74f03825a5..af342f219ec 100644
--- a/sysdeps/unix/sysv/linux/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/gettimeofday.c
@@ -32,8 +32,65 @@ 
 int
 __gettimeofday (struct timeval *tv, struct timezone *tz)
 {
-  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+  long int ret_64;
+#ifdef __ASSUME_TIME64_SYSCALLS
+# ifndef __NR_clock_gettime64
+#  define __NR_clock_gettime64 __NR_clock_gettime
+# endif
+  struct timespec now;
+
+  ret_64 = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
+                         &now);
+
+  if (ret_64 == 0 || errno != ENOSYS)
+    valid_timespec64_to_timeval((struct __timespec64*) &now, tv);
+
+  return ret_64;
+#else
+# ifdef __NR_clock_gettime64
+  ret_64 = INLINE_VSYSCALL (clock_gettime64, 2, CLOCK_REALTIME,
+                         &now);
+
+  if (ret_64 == 0 || errno != ENOSYS)
+    {
+      valid_timespec64_to_timeval((struct __timespec64*) &now, tv);
+      return ret_64;
+    }
+# endif /* __NR_clock_gettime64 */
+  int ret = INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+
+  if (! in_time_t_range (tv->tv_sec))
+    {
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+
+  return ret;
+#endif
 }
+
+#if __TIMESIZE != 64
+int
+__gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+  int ret;
+  timeval64 tv64;
+  struct __timespec64 now;
+
+  ret = __gettimeofday (&tv64, tz);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      /* Convert from timespec to timeval */
+      tv->tv_sec = tv64.tv_sec;
+      tv->tv_usec = tv64.tv_nsec;
+      return ret;
+    }
+
+  return ret;
+}
+#endif
+
 libc_hidden_def (__gettimeofday)
 weak_alias (__gettimeofday, gettimeofday)
 libc_hidden_weak (gettimeofday)