Patchwork [6/6] y2038: linux: Provide __clock_nanosleep64 implementation

login
register
mail settings
Submitter Lukasz Majewski
Date April 14, 2019, 10:08 p.m.
Message ID <20190414220841.20243-7-lukma@denx.de>
Download mbox | patch
Permalink /patch/32288/
State New
Headers show

Comments

Lukasz Majewski - April 14, 2019, 10:08 p.m.
This patch provides new __clock_nanosleep64 explicit 64 bit function
for sleeping specified time on specified clock ID. Moreover, a
32 bit version - __clock_nanosleep has been refactored to internally
use __clock_nanosleep64.

The __clock_nanosleep is now supposed to be used on 32 bit systems -
hence the necessary checks and conversions to 64 bit type. After this
change it is intrinsically Y2038 safe.

The new 64 bit syscall (clock_nanosleep_time64) available from Linux
5.1+ has been used when applicable on 32 bit systems.
The execution path on 64 bit systems has not been changed or affected
in any way.

Tests:
- The code has been tested with x86_64/x86 (native compilation):
make PARALLELMFLAGS="-j8" && make xcheck PARALLELMFLAGS="-j8"

- Run specific tests on ARM/x86 32bit systems (qemu):
https://github.com/lmajewski/meta-y2038
and run tests:
https://github.com/lmajewski/y2038-tests/commits/master
on kernels with and without 64 bit time support.

No regressions were observed.

* include/time.h (__clock_nanosleep64):
  Add __clock_nanosleep alias according to __TIMESIZE define
* sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep):
  Refactor this function to be used only on 32 bit machines as a
  wrapper on __clock_nanosleep64.
* sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep64):
  Add
* sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep64):
  Use clock_nanosleep_time64 kernel syscall (available from
  5.1-rc1+ Linux) by 32 bit Y2038 safe systems
---
 include/time.h                            |  9 ++++++
 sysdeps/unix/sysv/linux/clock_nanosleep.c | 52 ++++++++++++++++++++++++++++---
 2 files changed, 57 insertions(+), 4 deletions(-)
Joseph Myers - April 17, 2019, 10:11 p.m.
On Mon, 15 Apr 2019, Lukasz Majewski wrote:

> +  if (! INTERNAL_SYSCALL_ERROR_P (r, err))
> +      valid_timespec_to_timespec64(&rem32, rem);

Missing space before '('.  Indentation in GNU style is two columns, so two 
levels of indentation should be four columns (you have two columns 
followed by six columns here).
Lukasz Majewski - April 18, 2019, 5:54 a.m.
Hi Joseph,

> On Mon, 15 Apr 2019, Lukasz Majewski wrote:
> 
> > +  if (! INTERNAL_SYSCALL_ERROR_P (r, err))
> > +      valid_timespec_to_timespec64(&rem32, rem);  
> 
> Missing space before '('.  Indentation in GNU style is two columns,
> so two levels of indentation should be four columns (you have two
> columns followed by six columns here).
> 

Thanks for spotting. I will fix it in v2.


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

Patch

diff --git a/include/time.h b/include/time.h
index 7176ddbb84..75f3456017 100644
--- a/include/time.h
+++ b/include/time.h
@@ -148,6 +148,15 @@  extern int __clock_getres64 (clockid_t clock_id,
 libc_hidden_proto (__clock_getres64);
 #endif
 
+#if __TIMESIZE == 64
+# define __clock_nanosleep64 __clock_nanosleep
+#else
+extern int __clock_nanosleep64 (clockid_t clock_id, int flags,
+                                const struct __timespec64 *req,
+                                struct __timespec64 *rem);
+libc_hidden_proto (__clock_nanosleep64);
+#endif
+
 /* Compute the `struct tm' representation of T,
    offset OFFSET seconds east of UTC,
    and store year, yday, mon, mday, wday, hour, min, sec into *TP.
diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 0cb6614dc9..3f99b5df00 100644
--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
+++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
@@ -25,8 +25,8 @@ 
 /* We can simply use the syscall.  The CPU clocks are not supported
    with this function.  */
 int
-__clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
-		   struct timespec *rem)
+__clock_nanosleep64 (clockid_t clock_id, int flags,
+                     const struct __timespec64 *req, struct __timespec64 *rem)
 {
   if (clock_id == CLOCK_THREAD_CPUTIME_ID)
     return EINVAL;
@@ -36,9 +36,53 @@  __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
   /* If the call is interrupted by a signal handler or encounters an error,
      it returns a positive value similar to errno.  */
   INTERNAL_SYSCALL_DECL (err);
+#if defined (__TIMESIZE) && __TIMESIZE != 64
+# if defined __NR_clock_nanosleep_time64
+  struct __timespec64 ts = *req;
+  ts.tv_pad = 0;
+  int r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
+                                   flags, &ts, rem);
+# else
+  struct timespec req32, rem32;
+  valid_timespec64_to_timespec(req, &req32);
+  int r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep, err, clock_id, flags,
+                                   &req32, &rem32);
+
+  if (! INTERNAL_SYSCALL_ERROR_P (r, err))
+      valid_timespec_to_timespec64(&rem32, rem);
+# endif
+#else
   int r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep, err, clock_id, flags,
-				   req, rem);
+                                   req, rem);
+#endif
   return (INTERNAL_SYSCALL_ERROR_P (r, err)
-	  ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
+          ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
 }
 weak_alias (__clock_nanosleep, clock_nanosleep)
+
+#if __TIMESIZE != 64
+int
+__clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
+                   struct timespec *rem)
+{
+  struct __timespec64 req64, rem64;
+  int retval;
+
+  if (! in_time_t_range (req->tv_sec))
+    {
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+
+  valid_timespec_to_timespec64 (req, &req64);
+  retval = __clock_nanosleep64 (clock_id, flags, &req64, &rem64);
+
+  if (! retval && rem && ! timespec64_to_timespec (&rem64, rem))
+    {
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+
+  return retval;
+}
+#endif