[6/6] y2038: linux: Provide __clock_nanosleep64 implementation
Commit Message
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(-)
Comments
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).
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
@@ -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.
@@ -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