[RFC,v4,05/24] sysdeps/clock_gettime: Use clock_gettime64 if avaliable

Message ID 84b269f1c4a8633e01bd623c07080143c70b785e.1565398513.git.alistair.francis@wdc.com
State New, archived
Headers

Commit Message

Alistair Francis Aug. 10, 2019, 1 a.m. UTC
  Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 sysdeps/unix/sysv/linux/clock_gettime.c | 62 ++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)
  

Comments

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

>  /* Get current value of CLOCK and store it in TP.  */
> +
>  int
>  __clock_gettime (clockid_t clock_id, struct timespec *tp)
>  {
> -  return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
> +
> +#ifdef __ASSUME_TIME64_SYSCALLS
> +   return INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
> +#else

This has the usual problems with missing conversions.
  
Alistair Francis Aug. 13, 2019, 11:44 p.m. UTC | #2
On Mon, Aug 12, 2019 at 12:46 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 9 Aug 2019, Alistair Francis wrote:
>
> >  /* Get current value of CLOCK and store it in TP.  */
> > +
> >  int
> >  __clock_gettime (clockid_t clock_id, struct timespec *tp)
> >  {
> > -  return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
> > +
> > +#ifdef __ASSUME_TIME64_SYSCALLS
> > +   return INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
> > +#else
>
> This has the usual problems with missing conversions.

I was under the impression (although possibly incorrectly) that if
__ASSUME_TIME64_SYSCALLS is defined we would have a 64-bit time_t. Is
__ASSUME_TIME64_SYSCALLS going to be defined on 32-bit architectures
that are still using a 32-bit time_t?

Alistair

>
> --
> Joseph S. Myers
> joseph@codesourcery.com
  
Joseph Myers Aug. 14, 2019, 4:37 p.m. UTC | #3
On Tue, 13 Aug 2019, Alistair Francis wrote:

> I was under the impression (although possibly incorrectly) that if
> __ASSUME_TIME64_SYSCALLS is defined we would have a 64-bit time_t. Is
> __ASSUME_TIME64_SYSCALLS going to be defined on 32-bit architectures
> that are still using a 32-bit time_t?

Yes.  --enable-kernel=5.1.0 is not an ABI-changing option; it only affects 
what syscalls glibc can assume to be present at runtime in the kernel it 
runs on.

__ASSUME_TIME64_SYSCALLS means only that certain syscalls using 64-bit 
time are assumed to be available: either suffixed versions such as 
__NR_clock_gettime64, or corresponding unsuffixed versions such as 
__NR_clock_gettime in the case where those use 64-bit time and have 
exactly the same semantics and so "#define __NR_clock_gettime64 
__NR_clock_gettime" is OK.  (Because the kernel headers must be at least 
as recent as the minimum kernel version used at runtime, it also implies 
that the kernel headers do define the syscall numbers - but as noted, the 
syscalls might be __NR_clock_gettime etc. rather than the suffixed 
versions.)

All four combinations of __ASSUME_TIME64_SYSCALLS and __TIMESIZE are 
valid.

1. __TIMESIZE == 64 and __ASSUME_TIME64_SYSCALLS defined means a glibc 
port does not support anything other than 64-bit time *as its userspace 
ABI*, with the minimum kernel version ensuring appropriate syscalls are 
available.  Cases of this include:

(a) Classic 64-bit systems (__WORDSIZE == 64, unsuffixed syscalls).

(b) x32 (__WORDSIZE == 32, __SYSCALL_WORDSIZE == 64, unsuffixed syscalls).

(c) New glibc ports with 32-bit "long int" in the syscall interface 
(__WORDSIZE == 32 and __SYSCALL_WORDSIZE == 32) but only supporting 64-bit 
time as its userspace ABI and with the configured minimum kernel version 
(5.1 or later) ensuring appropriate (suffixed) syscalls are available (and 
unsuffixed ones don't exist at all).  This is the case that applies to 
RV32.

2. __TIMESIZE == 64 and __ASSUME_TIME64_SYSCALLS not defined means a glibc 
port that does not support anything other than 64-bit time *as its 
userspace ABI*, but with the minimum kernel version not ensuring 
appropriate syscalls are available.  This implies __WORDSIZE == 32 and 
__SYSCALL_WORDSIZE == 32.  This is a hypothetical case, if a new glibc 
port were added for a 32-bit architecture that was supported in the Linux 
kernel before 5.1, and if it were chosen to have 64-bit time as the 
userspace ABI for this port but to support using kernels before 5.1.  As 
it's hypothetical, it's not something you're expected to test unless 
adding such a port - but most of the support for it should naturally fall 
out from the Y2038 implementation anyway (the support for 64-bit 
interfaces to use 32-bit syscalls when run on older kernels).

3. __TIMESIZE == 32 and __ASSUME_TIME64_SYSCALLS defined means a 32-bit 
glibc port, where the unsuffixed time-related ABIs in glibc use 32-bit 
time but the Y2038 work will add corresponding suffixed ABIs (and 
_TIME_BITS headers support) that use 64-bit time - and where the minimum 
kernel version ensures 64-bit-time (suffixed) syscalls are available.  So 
the suffixed ABIs for 64-bit time can call those suffixed syscalls 
unconditionally, but the unsuffixed ABIs need to do appropriate 
translation between 32-bit and 64-bit time to call those syscalls (and the 
expected design is that the unsuffixed ABIs will generally be thin 
wrappers that do such translation and call the suffixed ones).

4. __TIMESIZE == 32 and __ASSUME_TIME64_SYSCALLS not defined means a 
32-bit glibc port, where the unsuffixed time-related ABIs in glibc use 
32-bit time but the Y2038 work will add corresponding suffixed ABIs (and 
_TIME_BITS headers support) that use 64-bit time - and where the minimum 
kernel version does not ensure that 64-bit-time (suffixed) syscalls are 
available.  Thus, the suffixed ABIs for 64-bit time need to have support 
for falling back to the 32-bit syscalls when the 64-bit ones are not 
available.
  
Alistair Francis Aug. 14, 2019, 6:08 p.m. UTC | #4
On Wed, Aug 14, 2019 at 9:37 AM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Tue, 13 Aug 2019, Alistair Francis wrote:
>
> > I was under the impression (although possibly incorrectly) that if
> > __ASSUME_TIME64_SYSCALLS is defined we would have a 64-bit time_t. Is
> > __ASSUME_TIME64_SYSCALLS going to be defined on 32-bit architectures
> > that are still using a 32-bit time_t?
>
> Yes.  --enable-kernel=5.1.0 is not an ABI-changing option; it only affects
> what syscalls glibc can assume to be present at runtime in the kernel it
> runs on.
>
> __ASSUME_TIME64_SYSCALLS means only that certain syscalls using 64-bit
> time are assumed to be available: either suffixed versions such as
> __NR_clock_gettime64, or corresponding unsuffixed versions such as
> __NR_clock_gettime in the case where those use 64-bit time and have
> exactly the same semantics and so "#define __NR_clock_gettime64
> __NR_clock_gettime" is OK.  (Because the kernel headers must be at least
> as recent as the minimum kernel version used at runtime, it also implies
> that the kernel headers do define the syscall numbers - but as noted, the
> syscalls might be __NR_clock_gettime etc. rather than the suffixed
> versions.)
>
> All four combinations of __ASSUME_TIME64_SYSCALLS and __TIMESIZE are
> valid.
>
> 1. __TIMESIZE == 64 and __ASSUME_TIME64_SYSCALLS defined means a glibc
> port does not support anything other than 64-bit time *as its userspace
> ABI*, with the minimum kernel version ensuring appropriate syscalls are
> available.  Cases of this include:
>
> (a) Classic 64-bit systems (__WORDSIZE == 64, unsuffixed syscalls).
>
> (b) x32 (__WORDSIZE == 32, __SYSCALL_WORDSIZE == 64, unsuffixed syscalls).
>
> (c) New glibc ports with 32-bit "long int" in the syscall interface
> (__WORDSIZE == 32 and __SYSCALL_WORDSIZE == 32) but only supporting 64-bit
> time as its userspace ABI and with the configured minimum kernel version
> (5.1 or later) ensuring appropriate (suffixed) syscalls are available (and
> unsuffixed ones don't exist at all).  This is the case that applies to
> RV32.
>
> 2. __TIMESIZE == 64 and __ASSUME_TIME64_SYSCALLS not defined means a glibc
> port that does not support anything other than 64-bit time *as its
> userspace ABI*, but with the minimum kernel version not ensuring
> appropriate syscalls are available.  This implies __WORDSIZE == 32 and
> __SYSCALL_WORDSIZE == 32.  This is a hypothetical case, if a new glibc
> port were added for a 32-bit architecture that was supported in the Linux
> kernel before 5.1, and if it were chosen to have 64-bit time as the
> userspace ABI for this port but to support using kernels before 5.1.  As
> it's hypothetical, it's not something you're expected to test unless
> adding such a port - but most of the support for it should naturally fall
> out from the Y2038 implementation anyway (the support for 64-bit
> interfaces to use 32-bit syscalls when run on older kernels).
>
> 3. __TIMESIZE == 32 and __ASSUME_TIME64_SYSCALLS defined means a 32-bit
> glibc port, where the unsuffixed time-related ABIs in glibc use 32-bit
> time but the Y2038 work will add corresponding suffixed ABIs (and
> _TIME_BITS headers support) that use 64-bit time - and where the minimum
> kernel version ensures 64-bit-time (suffixed) syscalls are available.  So
> the suffixed ABIs for 64-bit time can call those suffixed syscalls
> unconditionally, but the unsuffixed ABIs need to do appropriate
> translation between 32-bit and 64-bit time to call those syscalls (and the
> expected design is that the unsuffixed ABIs will generally be thin
> wrappers that do such translation and call the suffixed ones).

Ok, I didn't realise that this was a possible case, I will update the series.

Alistair

>
> 4. __TIMESIZE == 32 and __ASSUME_TIME64_SYSCALLS not defined means a
> 32-bit glibc port, where the unsuffixed time-related ABIs in glibc use
> 32-bit time but the Y2038 work will add corresponding suffixed ABIs (and
> _TIME_BITS headers support) that use 64-bit time - and where the minimum
> kernel version does not ensure that 64-bit-time (suffixed) syscalls are
> available.  Thus, the suffixed ABIs for 64-bit time need to have support
> for falling back to the 32-bit syscalls when the 64-bit ones are not
> available.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
  

Patch

diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
index 5fc47fb7dc7..c090797e461 100644
--- a/sysdeps/unix/sysv/linux/clock_gettime.c
+++ b/sysdeps/unix/sysv/linux/clock_gettime.c
@@ -27,10 +27,70 @@ 
 #include <sysdep-vdso.h>
 
 /* Get current value of CLOCK and store it in TP.  */
+
 int
 __clock_gettime (clockid_t clock_id, struct timespec *tp)
 {
-  return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
+
+#ifdef __ASSUME_TIME64_SYSCALLS
+   return INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
+#else
+   int ret;
+# ifdef __NR_clock_gettime64
+#  if __TIMESIZE == 64
+  ret = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      return ret;
+    }
+#  else
+  struct __timespec64 tp64;
+  ret = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, &tp64);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      tp->tv_sec = tp64.tv_sec;
+      tp->tv_nsec = tp64.tv_nsec;
+      if (! in_time_t_range (tp->tv_sec))
+        {
+          __set_errno (EOVERFLOW);
+          return -1;
+        }
+
+      return 0;
+    }
+#  endif /* __TIMESIZE == 64 */
+# endif /* __NR_clock_gettime64 */
+# if __TIMESIZE == 64
+  struct timespec ts32;
+
+  if (! in_time_t_range (tp->tv_sec))
+    {
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+
+  ret = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32);
+
+  if (ret == 0 || errno != ENOSYS)
+    {
+      tp->tv_sec = ts32.tv_sec;
+      tp->tv_nsec = ts32.tv_nsec;
+      if (! in_time_t_range (tp->tv_sec))
+        {
+          __set_errno (EOVERFLOW);
+          return -1;
+        }
+
+      return 0;
+    }
+  return ret;
+# else
+    return INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
+# endif /* __TIMESIZE == 64 */
+#endif /* __ASSUME_TIME64_SYSCALLS */
 }
+
 weak_alias (__clock_gettime, clock_gettime)
 libc_hidden_def (__clock_gettime)