From ecf2661281c71a9752c7238ab93bc12b16cfff23 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 15 Jun 2021 15:41:00 -0300 Subject: [PATCH] linux: Only use 64-bit syscall if required for ppoll For !__ASSUME_TIME64_SYSCALLS there is no need to issue a 64-bit syscall if the provided timeout fits in a 32-bit one. The 64-bit usage should be rare since the timeout is a relative one. This also avoids the need to use supports_time64() (which breaks the usage case of live migration like CRIU or similar). Checked on i686-linux-gnu on a 4.15 kernel and on a 5.11 kernel (with and without --enable-kernel=5.1) and on x86_64-linux-gnu. Reviewed-by: Lukasz Majewski --- sysdeps/unix/sysv/linux/Makefile | 9 +++++++ sysdeps/unix/sysv/linux/ppoll.c | 40 +++++++++++------------------ sysdeps/unix/sysv/linux/tst-ppoll.c | 15 +++++++++++ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 294c366e3b..c36ea0e494 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -137,6 +137,15 @@ tests-time64 += \ CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables +ifeq (yes,$(build-shared)) +librt = $(common-objpfx)rt/librt.so +else +librt = $(common-objpfx)rt/librt.a +endif + +$(objpfx)tst-ppoll: $(librt) +$(objpfx)tst-ppoll-time64: $(librt) + # Generate the list of SYS_* macros for the system calls (__NR_* # macros). The file syscall-names.list contains all possible system # call names, and the generated header file produces SYS_* macros for diff --git a/sysdeps/unix/sysv/linux/ppoll.c b/sysdeps/unix/sysv/linux/ppoll.c index 624f14f517..8ca133b1fa 100644 --- a/sysdeps/unix/sysv/linux/ppoll.c +++ b/sysdeps/unix/sysv/linux/ppoll.c @@ -21,9 +21,6 @@ #include #include #include -#include -#include - int __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout, @@ -38,40 +35,33 @@ __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout, timeout = &tval; } - int ret; - - if (supports_time64 ()) - { #ifndef __NR_ppoll_time64 # define __NR_ppoll_time64 __NR_ppoll #endif + +#ifdef __ASSUME_TIME64_SYSCALLS + return SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask, + __NSIG_BYTES); +#else + int ret; + bool need_time64 = timeout != NULL && !in_time_t_range (timeout->tv_sec); + if (need_time64) + { ret = SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask, __NSIG_BYTES); - if (ret == 0 || errno != ENOSYS) return ret; - - mark_time64_unsupported (); + __set_errno (EOVERFLOW); + return -1; } -#ifndef __ASSUME_TIME64_SYSCALLS struct timespec ts32; - if (timeout) - { - if (! in_time_t_range (timeout->tv_sec)) - { - __set_errno (EOVERFLOW); - return -1; - } + if (timeout != NULL) + ts32 = valid_timespec64_to_timespec (*timeout); - ts32 = valid_timespec64_to_timespec (*timeout); - } - - ret = SYSCALL_CANCEL (ppoll, fds, nfds, timeout ? &ts32 : NULL, sigmask, - __NSIG_BYTES); + return SYSCALL_CANCEL (ppoll, fds, nfds, timeout ? &ts32 : NULL, sigmask, + __NSIG_BYTES); #endif - - return ret; } #if __TIMESIZE != 64 diff --git a/sysdeps/unix/sysv/linux/tst-ppoll.c b/sysdeps/unix/sysv/linux/tst-ppoll.c index 9fe6ad07ce..e21e2fcc72 100644 --- a/sysdeps/unix/sysv/linux/tst-ppoll.c +++ b/sysdeps/unix/sysv/linux/tst-ppoll.c @@ -19,9 +19,11 @@ #include #include #include +#include #include #include #include +#include #include static int test_ppoll_timeout (bool zero_tmo) @@ -41,6 +43,16 @@ static int test_ppoll_timeout (bool zero_tmo) return 0; } +static void +test_ppoll_large_timeout (void) +{ + support_create_timer (0, 100000000, false, NULL); + struct timespec ts = { TYPE_MAXIMUM (time_t), 0 }; + struct pollfd fds = { -1, 0, 0 }; + TEST_COMPARE (ppoll (&fds, 1, &ts, 0), -1); + TEST_VERIFY (errno == EINTR || errno == EOVERFLOW); +} + static int do_test (void) { @@ -50,6 +62,9 @@ do_test (void) /* Check if ppoll exits after specified timeout. */ test_ppoll_timeout (false); + /* Check if ppoll with large timeout. */ + test_ppoll_large_timeout (); + return 0; }