summaryrefslogtreecommitdiffstats
path: root/source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch
diff options
context:
space:
mode:
Diffstat (limited to 'source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch')
-rw-r--r--source/l/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch237
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 000000000..96f56ce73
--- /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
+
+