diff options
Diffstat (limited to 'source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch')
-rw-r--r-- | source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch b/source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch new file mode 100644 index 00000000..96f56ce7 --- /dev/null +++ b/source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch @@ -0,0 +1,237 @@ +From cdc31409bd4f878577059e70dbd52a28643ec609 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella <adhemerval.zanella@linaro.org> +Date: Wed, 31 Mar 2021 13:53:34 -0300 +Subject: [PATCH] linux: Normalize and return timeout on select (BZ #27651) + +The commit 2433d39b697, which added time64 support to select, changed +the function to use __NR_pselect6 (or __NR_pelect6_time64) on all +architectures. However, on architectures where the symbol was +implemented with __NR_select the kernel normalizes the passed timeout +instead of return EINVAL. For instance, the input timeval +{ 0, 5000000 } is interpreted as { 5, 0 }. + +And as indicated by BZ #27651, this semantic seems to be expected +and changing it results in some performance issues (most likely +the program does not check the return code and keeps issuing +select with unormalized tv_usec argument). + +To avoid a different semantic depending whether which syscall the +architecture used to issue, select now always normalize the timeout +input. This is a slight change for some ABIs (for instance aarch64). + +Checked on x86_64-linux-gnu and i686-linux-gnu. +--- + include/time.h | 5 +++ + sunrpc/svcauth_des.c | 1 - + support/Makefile | 2 ++ + support/support.h | 8 +++++ + support/support_select_modify_timeout.c | 29 ++++++++++++++++ + support/support_select_normalize_timeout.c | 29 ++++++++++++++++ + sysdeps/unix/sysv/linux/select.c | 40 ++++++++++++++++++---- + 8 files changed, 123 insertions(+), 8 deletions(-) + create mode 100644 support/support_select_modify_timeout.c + create mode 100644 support/support_select_normalize_timeout.c + +diff --git a/include/time.h b/include/time.h +index caf2af5e74..e0636132a6 100644 +--- a/include/time.h ++++ b/include/time.h +@@ -502,6 +502,11 @@ time_now (void) + __clock_gettime (TIME_CLOCK_GETTIME_CLOCKID, &ts); + return ts.tv_sec; + } ++ ++#define NSEC_PER_SEC 1000000000L /* Nanoseconds per second. */ ++#define USEC_PER_SEC 1000000L /* Microseconds per second. */ ++#define NSEC_PER_USEC 1000L /* Nanoseconds per microsecond. */ ++ + #endif + + #endif +diff --git a/sunrpc/svcauth_des.c b/sunrpc/svcauth_des.c +index 7607abc818..25a85c9097 100644 +--- a/sunrpc/svcauth_des.c ++++ b/sunrpc/svcauth_des.c +@@ -58,7 +58,6 @@ + + #define debug(msg) /*printf("svcauth_des: %s\n", msg) */ + +-#define USEC_PER_SEC ((uint32_t) 1000000L) + #define BEFORE(t1, t2) timercmp(t1, t2, <) + + /* +diff --git a/support/Makefile b/support/Makefile +index 900e17f94f..1e2fc97ee6 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -68,6 +68,8 @@ libsupport-routines = \ + support_quote_string \ + support_record_failure \ + support_run_diff \ ++ support_select_modify_timeout \ ++ support_select_normalize_timeout \ + support_set_small_thread_stack_size \ + support_shared_allocate \ + support_small_stack_thread_attribute \ +diff --git a/support/support.h b/support/support.h +index e023d00857..f983783d64 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -144,6 +144,14 @@ static __inline bool support_path_support_time64 (const char *path) + /* Return true if stat supports nanoseconds resolution. */ + extern bool support_stat_nanoseconds (const char *path); + ++/* Return true if select modify the timeout to reflect the amount of time ++ no slept. */ ++extern bool support_select_modify_timeout (void); ++ ++/* Return true if select normalize the timeout input by taking in account ++ tv_usec larger than 1000000. */ ++extern bool support_select_normalize_timeout (void); ++ + __END_DECLS + + #endif /* SUPPORT_H */ +diff --git a/support/support_select_modify_timeout.c b/support/support_select_modify_timeout.c +new file mode 100644 +index 0000000000..d70a5a5068 +--- /dev/null ++++ b/support/support_select_modify_timeout.c +@@ -0,0 +1,29 @@ ++/* Return whether select modify the timeout. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stdbool.h> ++ ++bool ++support_select_modify_timeout (void) ++{ ++#ifdef __linux__ ++ return true; ++#else ++ return false; ++#endif ++} +diff --git a/support/support_select_normalize_timeout.c b/support/support_select_normalize_timeout.c +new file mode 100644 +index 0000000000..447e3ec3e3 +--- /dev/null ++++ b/support/support_select_normalize_timeout.c +@@ -0,0 +1,29 @@ ++/* Return whether select normalize the timeout. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stdbool.h> ++ ++bool ++support_select_normalize_timeout (void) ++{ ++#ifdef __linux__ ++ return true; ++#else ++ return false; ++#endif ++} +diff --git a/sysdeps/unix/sysv/linux/select.c b/sysdeps/unix/sysv/linux/select.c +index 415aa87d3c..d075270ff4 100644 +--- a/sysdeps/unix/sysv/linux/select.c ++++ b/sysdeps/unix/sysv/linux/select.c +@@ -33,12 +33,34 @@ int + __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct __timeval64 *timeout) + { +- struct __timespec64 ts64, *pts64 = NULL; +- if (timeout != NULL) ++ __time64_t s = timeout != NULL ? timeout->tv_sec : 0; ++ int32_t us = timeout != NULL ? timeout->tv_usec : 0; ++ int32_t ns; ++ ++ if (s < 0 || us < 0) ++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL); ++ ++ /* Normalize the timeout, as legacy Linux __NR_select and __NR__newselect. ++ Different than syscall, it also handle possible overflow. */ ++ if (us / USEC_PER_SEC > INT64_MAX - s) + { +- ts64 = timeval64_to_timespec64 (*timeout); +- pts64 = &ts64; ++ s = INT64_MAX; ++ ns = NSEC_PER_SEC - 1; + } ++ else ++ { ++ s += us / USEC_PER_SEC; ++ us = us % USEC_PER_SEC; ++ ns = us * NSEC_PER_USEC; ++ } ++ ++ struct __timespec64 ts64, *pts64 = NULL; ++ if (timeout != NULL) ++ { ++ ts64.tv_sec = s; ++ ts64.tv_nsec = ns; ++ pts64 = &ts64; ++ } + + #ifndef __NR_pselect6_time64 + # define __NR_pselect6_time64 __NR_pselect6 +@@ -52,10 +74,13 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + (though the pselect() glibc call suppresses this behavior). + Since select() on Linux has the same behavior as the pselect6 + syscall, we update the timeout here. */ +- if (r == 0 || errno != ENOSYS) ++ if (r >= 0 || errno != ENOSYS) + { + if (timeout != NULL) +- TIMEVAL_TO_TIMESPEC (timeout, &ts64); ++ { ++ timeout->tv_sec = ts64.tv_sec; ++ timeout->tv_usec = ts64.tv_nsec / NSEC_PER_USEC; ++ } + return r; + } + +@@ -71,7 +96,8 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + __set_errno (EINVAL); + return -1; + } +- ts32 = valid_timespec64_to_timespec (ts64); ++ ts32.tv_sec = s; ++ ts32.tv_nsec = ns; + pts32 = &ts32; + } + # ifndef __ASSUME_PSELECT +-- +2.27.0 + + |